mirror of
https://github.com/maxartz15/VolumetricLighting.git
synced 2024-12-22 06:28:27 +01:00
Added the project.
This commit is contained in:
parent
93760b331c
commit
947b6de3a5
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
/Library
|
||||
/Temp
|
||||
*.sln
|
||||
*.csproj
|
9
Assets/AreaLight.meta
Normal file
9
Assets/AreaLight.meta
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 692b74bd11c622b4ab56587cf3ebc53a
|
||||
folderAsset: yes
|
||||
timeCreated: 1476957694
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
179
Assets/AreaLight/AreaLight.prefab
Normal file
179
Assets/AreaLight/AreaLight.prefab
Normal file
@ -0,0 +1,179 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1001 &100100000
|
||||
Prefab:
|
||||
m_ObjectHideFlags: 1
|
||||
serializedVersion: 2
|
||||
m_Modification:
|
||||
m_TransformParent: {fileID: 0}
|
||||
m_Modifications:
|
||||
- target: {fileID: 0}
|
||||
propertyPath: m_ProxyShader
|
||||
value:
|
||||
objectReference: {fileID: 4800000, guid: 2b28be3523d190a41910088d1ee68ef7, type: 3}
|
||||
- target: {fileID: 0}
|
||||
propertyPath: m_Cube
|
||||
value:
|
||||
objectReference: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
|
||||
- target: {fileID: 0}
|
||||
propertyPath: m_LocalPosition.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 0}
|
||||
propertyPath: m_LocalPosition.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 0}
|
||||
propertyPath: m_LocalPosition.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 0}
|
||||
propertyPath: m_LocalRotation.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 0}
|
||||
propertyPath: m_LocalRotation.w
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 0}
|
||||
propertyPath: m_Intensity
|
||||
value: 0.8
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 0}
|
||||
propertyPath: m_BlurShadowmapShader
|
||||
value:
|
||||
objectReference: {fileID: 4800000, guid: 701192b62a7678549918bc87434699fe, type: 3}
|
||||
- target: {fileID: 0}
|
||||
propertyPath: m_ShadowmapRes
|
||||
value: 2048
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 0}
|
||||
propertyPath: m_Shadows
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
m_RemovedComponents: []
|
||||
m_ParentPrefab: {fileID: 0}
|
||||
m_RootGameObject: {fileID: 1000010046428508}
|
||||
m_IsPrefabParent: 1
|
||||
--- !u!1 &1000010046428508
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
serializedVersion: 4
|
||||
m_Component:
|
||||
- 4: {fileID: 4000014113918066}
|
||||
- 114: {fileID: 114000011647635530}
|
||||
- 33: {fileID: 33000012356353452}
|
||||
- 23: {fileID: 23000012433474804}
|
||||
- 114: {fileID: 114000013519192348}
|
||||
m_Layer: 0
|
||||
m_Name: AreaLight
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &4000014113918066
|
||||
Transform:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1000010046428508}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
--- !u!23 &23000012433474804
|
||||
MeshRenderer:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1000010046428508}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 1
|
||||
m_ReceiveShadows: 1
|
||||
m_MotionVectors: 1
|
||||
m_LightProbeUsage: 0
|
||||
m_ReflectionProbeUsage: 1
|
||||
m_Materials:
|
||||
- {fileID: 2100000, guid: 1eb056d70e23cc34a9e926d8c8c887a5, type: 2}
|
||||
m_SubsetIndices:
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_PreserveUVs: 1
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_SelectedWireframeHidden: 0
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_SortingLayerID: 0
|
||||
m_SortingOrder: 0
|
||||
--- !u!33 &33000012356353452
|
||||
MeshFilter:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1000010046428508}
|
||||
m_Mesh: {fileID: 0}
|
||||
--- !u!114 &114000011647635530
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1000010046428508}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 792909cacf2415c48a1d7eebef426b5d, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Cube: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
|
||||
m_ProxyShader: {fileID: 4800000, guid: 2b28be3523d190a41910088d1ee68ef7, type: 3}
|
||||
m_ShadowmapShader: {fileID: 4800000, guid: 2c4cd42b134f7864fa579350e9cf6896, type: 3}
|
||||
m_BlurShadowmapShader: {fileID: 4800000, guid: 701192b62a7678549918bc87434699fe,
|
||||
type: 3}
|
||||
m_RenderSource: 1
|
||||
m_Size: {x: 2, y: 2, z: 6}
|
||||
m_Angle: 100
|
||||
m_Intensity: 0.8
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_Shadows: 0
|
||||
m_ShadowCullingMask:
|
||||
serializedVersion: 2
|
||||
m_Bits: 4294967295
|
||||
m_ShadowmapRes: 2048
|
||||
m_ReceiverSearchDistance: 24
|
||||
m_ReceiverDistanceScale: 5
|
||||
m_LightNearSize: 4
|
||||
m_LightFarSize: 22
|
||||
m_ShadowBias: 0.02
|
||||
m_Quad: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0}
|
||||
--- !u!114 &114000013519192348
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1000010046428508}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 097385f2a510795498370c4d62e61572, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_IntensityMult: 1
|
||||
m_RangeMult: 1
|
||||
m_BlurShadowmapShader: {fileID: 0}
|
||||
m_CopyShadowParamsShader: {fileID: 0}
|
||||
m_ForceOnForFog: 0
|
||||
m_Shadows: 0
|
||||
m_ShadowmapRes: 512
|
||||
m_BlurIterations: 0
|
||||
m_BlurSize: 1
|
||||
m_ESMExponent: 40
|
||||
m_Bounded: 1
|
8
Assets/AreaLight/AreaLight.prefab.meta
Normal file
8
Assets/AreaLight/AreaLight.prefab.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c946fa75949b4b0469e29c6e49bd3577
|
||||
timeCreated: 1450870880
|
||||
licenseType: Pro
|
||||
NativeFormatImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
9
Assets/AreaLight/Scripts.meta
Normal file
9
Assets/AreaLight/Scripts.meta
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 26b199722eb73ad45b1ee21d58a9242f
|
||||
folderAsset: yes
|
||||
timeCreated: 1477748665
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
143
Assets/AreaLight/Scripts/AreaLight.Direct.cs
Normal file
143
Assets/AreaLight/Scripts/AreaLight.Direct.cs
Normal file
@ -0,0 +1,143 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public partial class AreaLight : MonoBehaviour
|
||||
{
|
||||
[HideInInspector]
|
||||
public Mesh m_Cube;
|
||||
[HideInInspector]
|
||||
public Shader m_ProxyShader;
|
||||
Material m_ProxyMaterial;
|
||||
static Texture2D s_TransformInvTexture_Specular;
|
||||
static Texture2D s_TransformInvTexture_Diffuse;
|
||||
static Texture2D s_AmpDiffAmpSpecFresnel;
|
||||
|
||||
Dictionary<Camera, CommandBuffer> m_Cameras = new Dictionary<Camera, CommandBuffer>();
|
||||
static CameraEvent kCameraEvent = CameraEvent.AfterLighting;
|
||||
|
||||
bool InitDirect()
|
||||
{
|
||||
if (m_ProxyShader == null || m_Cube == null)
|
||||
return false;
|
||||
|
||||
// Proxy
|
||||
m_ProxyMaterial = new Material(m_ProxyShader);
|
||||
m_ProxyMaterial.hideFlags = HideFlags.HideAndDontSave;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SetUpLUTs()
|
||||
{
|
||||
if (s_TransformInvTexture_Diffuse == null)
|
||||
s_TransformInvTexture_Diffuse = AreaLightLUT.LoadLUT(AreaLightLUT.LUTType.TransformInv_DisneyDiffuse);
|
||||
if (s_TransformInvTexture_Specular == null)
|
||||
s_TransformInvTexture_Specular = AreaLightLUT.LoadLUT(AreaLightLUT.LUTType.TransformInv_GGX);
|
||||
if (s_AmpDiffAmpSpecFresnel == null)
|
||||
s_AmpDiffAmpSpecFresnel = AreaLightLUT.LoadLUT(AreaLightLUT.LUTType.AmpDiffAmpSpecFresnel);
|
||||
|
||||
m_ProxyMaterial.SetTexture("_TransformInv_Diffuse", s_TransformInvTexture_Diffuse);
|
||||
m_ProxyMaterial.SetTexture("_TransformInv_Specular", s_TransformInvTexture_Specular);
|
||||
m_ProxyMaterial.SetTexture("_AmpDiffAmpSpecFresnel", s_AmpDiffAmpSpecFresnel);
|
||||
}
|
||||
|
||||
void Cleanup()
|
||||
{
|
||||
for(var e = m_Cameras.GetEnumerator(); e.MoveNext();)
|
||||
{
|
||||
var cam = e.Current;
|
||||
if (cam.Key != null && cam.Value != null)
|
||||
{
|
||||
cam.Key.RemoveCommandBuffer (kCameraEvent, cam.Value);
|
||||
}
|
||||
}
|
||||
m_Cameras.Clear();
|
||||
}
|
||||
|
||||
static readonly float[,] offsets = new float[4,2] {{1, 1}, {1, -1}, {-1, -1}, {-1, 1}};
|
||||
|
||||
CommandBuffer GetOrCreateCommandBuffer(Camera cam)
|
||||
{
|
||||
if(cam == null)
|
||||
return null;
|
||||
|
||||
CommandBuffer buf = null;
|
||||
if(!m_Cameras.ContainsKey(cam)) {
|
||||
buf = new CommandBuffer();
|
||||
buf.name = /*"Area light: " +*/ gameObject.name;
|
||||
m_Cameras[cam] = buf;
|
||||
cam.AddCommandBuffer(kCameraEvent, buf);
|
||||
cam.depthTextureMode |= DepthTextureMode.Depth;
|
||||
} else {
|
||||
buf = m_Cameras[cam];
|
||||
buf.Clear();
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
public void SetUpCommandBuffer()
|
||||
{
|
||||
if (InsideShadowmapCameraRender())
|
||||
return;
|
||||
|
||||
Camera cam = Camera.current;
|
||||
CommandBuffer buf = GetOrCreateCommandBuffer(cam);
|
||||
|
||||
buf.SetGlobalVector("_LightPos", transform.position);
|
||||
buf.SetGlobalVector("_LightColor", GetColor());
|
||||
SetUpLUTs();
|
||||
|
||||
// Needed as we're using the vert_deferred vertex shader from UnityDeferredLibrary.cginc
|
||||
// TODO: Make the light render as quad if it intersects both near and far plane.
|
||||
// (Also missing: rendering as front faces when near doesn't intersect, stencil optimisations)
|
||||
buf.SetGlobalFloat("_LightAsQuad", 0);
|
||||
|
||||
// A little bit of bias to prevent the light from lighting itself - the source quad
|
||||
float z = 0.01f;
|
||||
Transform t = transform;
|
||||
|
||||
Matrix4x4 lightVerts = new Matrix4x4();
|
||||
for (int i = 0; i < 4; i++)
|
||||
lightVerts.SetRow(i, t.TransformPoint(new Vector3(m_Size.x * offsets[i,0], m_Size.y * offsets[i,1], z) * 0.5f));
|
||||
buf.SetGlobalMatrix("_LightVerts", lightVerts);
|
||||
|
||||
if (m_Shadows)
|
||||
SetUpShadowmapForSampling(buf);
|
||||
|
||||
Matrix4x4 m = Matrix4x4.TRS(new Vector3(0, 0, 10.0f), Quaternion.identity, Vector3.one * 20);
|
||||
buf.DrawMesh(m_Cube, t.localToWorldMatrix * m, m_ProxyMaterial, 0, m_Shadows ? /*shadows*/ 0 : /*no shadows*/ 1);
|
||||
}
|
||||
|
||||
void SetKeyword(string keyword, bool on)
|
||||
{
|
||||
if (on)
|
||||
m_ProxyMaterial.EnableKeyword(keyword);
|
||||
else
|
||||
m_ProxyMaterial.DisableKeyword(keyword);
|
||||
}
|
||||
|
||||
void ReleaseTemporary(ref RenderTexture rt)
|
||||
{
|
||||
if (rt == null)
|
||||
return;
|
||||
|
||||
RenderTexture.ReleaseTemporary(rt);
|
||||
rt = null;
|
||||
}
|
||||
|
||||
Color GetColor()
|
||||
{
|
||||
if (QualitySettings.activeColorSpace == ColorSpace.Gamma)
|
||||
return m_Color * m_Intensity;
|
||||
|
||||
return new Color(
|
||||
Mathf.GammaToLinearSpace(m_Color.r * m_Intensity),
|
||||
Mathf.GammaToLinearSpace(m_Color.g * m_Intensity),
|
||||
Mathf.GammaToLinearSpace(m_Color.b * m_Intensity),
|
||||
1.0f
|
||||
);
|
||||
}
|
||||
|
||||
}
|
12
Assets/AreaLight/Scripts/AreaLight.Direct.cs.meta
Normal file
12
Assets/AreaLight/Scripts/AreaLight.Direct.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f166f8247b9668b45bd44bb7d17f3e1d
|
||||
timeCreated: 1453074905
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
303
Assets/AreaLight/Scripts/AreaLight.Shadow.cs
Normal file
303
Assets/AreaLight/Scripts/AreaLight.Shadow.cs
Normal file
@ -0,0 +1,303 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
public partial class AreaLight : MonoBehaviour
|
||||
{
|
||||
Camera m_ShadowmapCamera;
|
||||
Transform m_ShadowmapCameraTransform;
|
||||
|
||||
[HideInInspector]
|
||||
public Shader m_ShadowmapShader;
|
||||
[HideInInspector]
|
||||
public Shader m_BlurShadowmapShader;
|
||||
Material m_BlurShadowmapMaterial;
|
||||
RenderTexture m_Shadowmap = null;
|
||||
RenderTexture m_BlurredShadowmap = null;
|
||||
Texture2D m_ShadowmapDummy = null;
|
||||
|
||||
int m_ShadowmapRenderTime = -1;
|
||||
int m_BlurredShadowmapRenderTime = -1;
|
||||
FogLight m_FogLight = null;
|
||||
|
||||
public enum TextureSize
|
||||
{
|
||||
x512 = 512,
|
||||
x1024 = 1024,
|
||||
x2048 = 2048,
|
||||
x4096 = 4096,
|
||||
}
|
||||
|
||||
void UpdateShadowmap(int res)
|
||||
{
|
||||
if (m_Shadowmap != null && m_ShadowmapRenderTime == Time.renderedFrameCount)
|
||||
return;
|
||||
|
||||
// Create the camera
|
||||
if (m_ShadowmapCamera == null)
|
||||
{
|
||||
if (m_ShadowmapShader == null)
|
||||
{
|
||||
Debug.LogError("AreaLight's shadowmap shader not assigned.", this);
|
||||
return;
|
||||
}
|
||||
|
||||
GameObject go = new GameObject("Shadowmap Camera");
|
||||
go.AddComponent(typeof(Camera));
|
||||
m_ShadowmapCamera = go.GetComponent<Camera>();
|
||||
go.hideFlags = HideFlags.HideAndDontSave;
|
||||
m_ShadowmapCamera.enabled = false;
|
||||
m_ShadowmapCamera.clearFlags = CameraClearFlags.SolidColor;
|
||||
m_ShadowmapCamera.renderingPath = RenderingPath.Forward;
|
||||
// exp(EXPONENT) for ESM, white for VSM
|
||||
// m_ShadowmapCamera.backgroundColor = new Color(Mathf.Exp(EXPONENT), 0, 0, 0);
|
||||
m_ShadowmapCamera.backgroundColor = Color.white;
|
||||
m_ShadowmapCameraTransform = go.transform;
|
||||
m_ShadowmapCameraTransform.parent = transform;
|
||||
m_ShadowmapCameraTransform.localRotation = Quaternion.identity;
|
||||
}
|
||||
|
||||
if (m_Angle == 0.0f)
|
||||
{
|
||||
m_ShadowmapCamera.orthographic = true;
|
||||
m_ShadowmapCameraTransform.localPosition = Vector3.zero;
|
||||
m_ShadowmapCamera.nearClipPlane = 0;
|
||||
m_ShadowmapCamera.farClipPlane = m_Size.z;
|
||||
m_ShadowmapCamera.orthographicSize = 0.5f * m_Size.y;
|
||||
m_ShadowmapCamera.aspect = m_Size.x / m_Size.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ShadowmapCamera.orthographic = false;
|
||||
float near = GetNearToCenter();
|
||||
m_ShadowmapCameraTransform.localPosition = -near * Vector3.forward;
|
||||
m_ShadowmapCamera.nearClipPlane = near;
|
||||
m_ShadowmapCamera.farClipPlane = near + m_Size.z;
|
||||
m_ShadowmapCamera.fieldOfView = m_Angle;
|
||||
m_ShadowmapCamera.aspect = m_Size.x / m_Size.y;
|
||||
}
|
||||
|
||||
ReleaseTemporary(ref m_Shadowmap);
|
||||
m_Shadowmap = RenderTexture.GetTemporary(res, res, 24, RenderTextureFormat.Shadowmap);
|
||||
m_Shadowmap.name = "AreaLight Shadowmap";
|
||||
m_Shadowmap.filterMode = FilterMode.Bilinear;
|
||||
m_Shadowmap.wrapMode = TextureWrapMode.Clamp;
|
||||
|
||||
m_ShadowmapCamera.targetTexture = m_Shadowmap;
|
||||
|
||||
// Clear. RenderWithShader() should clear too, but it doesn't.
|
||||
// TODO: Check if it's a bug.
|
||||
m_ShadowmapCamera.cullingMask = 0;
|
||||
m_ShadowmapCamera.Render();
|
||||
m_ShadowmapCamera.cullingMask = m_ShadowCullingMask;
|
||||
|
||||
// We might be rendering inside PlaneReflections, which invert culling. Disable temporarily.
|
||||
var oldCulling = GL.invertCulling;
|
||||
GL.invertCulling = false;
|
||||
|
||||
m_ShadowmapCamera.RenderWithShader(m_ShadowmapShader, "RenderType");
|
||||
|
||||
// Back to whatever was the culling mode.
|
||||
GL.invertCulling = oldCulling;
|
||||
|
||||
m_ShadowmapRenderTime = Time.renderedFrameCount;
|
||||
}
|
||||
|
||||
public RenderTexture GetBlurredShadowmap()
|
||||
{
|
||||
UpdateBlurredShadowmap();
|
||||
return m_BlurredShadowmap;
|
||||
}
|
||||
|
||||
RenderTexture[] temp;
|
||||
|
||||
void UpdateBlurredShadowmap()
|
||||
{
|
||||
if (m_BlurredShadowmap != null && m_BlurredShadowmapRenderTime == Time.renderedFrameCount)
|
||||
return;
|
||||
|
||||
InitFogLight();
|
||||
|
||||
int startRes = (int)m_ShadowmapRes;
|
||||
int targetRes = (int)m_FogLight.m_ShadowmapRes;
|
||||
|
||||
// To make things easier, blurred shadowmap is at most half the size of the regular.
|
||||
if (isActiveAndEnabled && m_Shadows)
|
||||
{
|
||||
targetRes = Mathf.Min(targetRes, startRes/2);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the area light or the shadows on it are disabled, we can
|
||||
// just get the most convenient resolution for us.
|
||||
startRes = 2 * startRes;
|
||||
}
|
||||
|
||||
UpdateShadowmap(startRes);
|
||||
|
||||
RenderTexture originalRT = RenderTexture.active;
|
||||
|
||||
// Downsample
|
||||
ReleaseTemporary(ref m_BlurredShadowmap);
|
||||
InitMaterial(ref m_BlurShadowmapMaterial, m_BlurShadowmapShader);
|
||||
int downsampleSteps = (int)Mathf.Log(startRes / targetRes, 2);
|
||||
if (temp == null || temp.Length != downsampleSteps)
|
||||
temp = new RenderTexture[downsampleSteps];
|
||||
// RFloat for ESM, RGHalf for VSM
|
||||
RenderTextureFormat format = RenderTextureFormat.RGHalf;
|
||||
|
||||
for(int i = 0, currentRes = startRes/2; i < downsampleSteps; i++)
|
||||
{
|
||||
temp[i] = RenderTexture.GetTemporary(currentRes, currentRes, 0, format, RenderTextureReadWrite.Linear);
|
||||
temp[i].name = "AreaLight Shadow Downsample";
|
||||
temp[i].filterMode = FilterMode.Bilinear;
|
||||
temp[i].wrapMode = TextureWrapMode.Clamp;
|
||||
m_BlurShadowmapMaterial.SetVector("_TexelSize", new Vector4(0.5f/currentRes, 0.5f/currentRes, 0, 0));
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
m_BlurShadowmapMaterial.SetTexture("_Shadowmap", m_Shadowmap);
|
||||
InitShadowmapDummy();
|
||||
m_BlurShadowmapMaterial.SetTexture("_ShadowmapDummy", m_ShadowmapDummy);
|
||||
m_BlurShadowmapMaterial.SetVector("_ZParams", GetZParams());
|
||||
m_BlurShadowmapMaterial.SetFloat("_ESMExponent", m_FogLight.m_ESMExponent);
|
||||
Blur(m_Shadowmap, temp[i], /*sample & convert shadowmap*/ 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_BlurShadowmapMaterial.SetTexture("_MainTex", temp[i - 1]);
|
||||
Blur(temp[i - 1], temp[i], /*regular sample*/ 1);
|
||||
}
|
||||
|
||||
currentRes /= 2;
|
||||
}
|
||||
|
||||
for (int i = 0; i < downsampleSteps - 1; i++)
|
||||
RenderTexture.ReleaseTemporary(temp[i]);
|
||||
|
||||
m_BlurredShadowmap = temp[downsampleSteps - 1];
|
||||
|
||||
// Blur
|
||||
if (m_FogLight.m_BlurIterations > 0)
|
||||
{
|
||||
RenderTexture tempBlur = RenderTexture.GetTemporary (targetRes, targetRes, 0, format, RenderTextureReadWrite.Linear);
|
||||
tempBlur.name = "AreaLight Shadow Blur";
|
||||
tempBlur.filterMode = FilterMode.Bilinear;
|
||||
tempBlur.wrapMode = TextureWrapMode.Clamp;
|
||||
|
||||
m_BlurShadowmapMaterial.SetVector("_MainTex_TexelSize", new Vector4(1.0f/targetRes, 1.0f/targetRes, 0, 0));
|
||||
|
||||
float blurSize = m_FogLight.m_BlurSize;
|
||||
for(int i = 0; i < m_FogLight.m_BlurIterations; i++)
|
||||
{
|
||||
m_BlurShadowmapMaterial.SetFloat ("_BlurSize", blurSize);
|
||||
Blur(m_BlurredShadowmap, tempBlur, /*vertical blur*/2);
|
||||
Blur(tempBlur, m_BlurredShadowmap, /*horizontal blur*/3);
|
||||
blurSize *= 1.2f;
|
||||
}
|
||||
|
||||
RenderTexture.ReleaseTemporary(tempBlur);
|
||||
}
|
||||
|
||||
RenderTexture.active = originalRT;
|
||||
|
||||
m_BlurredShadowmapRenderTime = Time.renderedFrameCount;
|
||||
}
|
||||
|
||||
// Normally would've used Graphics.Blit(), but it breaks picking in the scene view.
|
||||
// TODO: bug report
|
||||
void Blur(RenderTexture src, RenderTexture dst, int pass)
|
||||
{
|
||||
RenderTexture.active = dst;
|
||||
m_BlurShadowmapMaterial.SetTexture("_MainTex", src);
|
||||
m_BlurShadowmapMaterial.SetPass(pass);
|
||||
RenderQuad();
|
||||
}
|
||||
|
||||
void RenderQuad()
|
||||
{
|
||||
GL.Begin(GL.QUADS);
|
||||
GL.TexCoord2( 0, 0);
|
||||
GL.Vertex3 (-1, 1, 0);
|
||||
GL.TexCoord2( 0, 1);
|
||||
GL.Vertex3 (-1,-1, 0);
|
||||
GL.TexCoord2( 1, 1);
|
||||
GL.Vertex3 ( 1,-1, 0);
|
||||
GL.TexCoord2( 1, 0);
|
||||
GL.Vertex3 ( 1, 1, 0);
|
||||
GL.End();
|
||||
}
|
||||
|
||||
void SetUpShadowmapForSampling(CommandBuffer buf)
|
||||
{
|
||||
UpdateShadowmap((int)m_ShadowmapRes);
|
||||
|
||||
buf.SetGlobalTexture("_Shadowmap", m_Shadowmap);
|
||||
InitShadowmapDummy();
|
||||
m_ProxyMaterial.SetTexture("_ShadowmapDummy", m_ShadowmapDummy);
|
||||
buf.SetGlobalMatrix("_ShadowProjectionMatrix", GetProjectionMatrix());
|
||||
|
||||
float texelsInMap = (int)m_ShadowmapRes;
|
||||
float relativeTexelSize = texelsInMap / 2048.0f;
|
||||
|
||||
buf.SetGlobalFloat("_ShadowReceiverWidth", relativeTexelSize * m_ReceiverSearchDistance / texelsInMap);
|
||||
|
||||
buf.SetGlobalFloat("_ShadowReceiverDistanceScale", m_ReceiverDistanceScale * 0.5f / 10.0f); // 10 samples in shader
|
||||
|
||||
Vector2 shadowLightWidth = new Vector2(m_LightNearSize, m_LightFarSize) * relativeTexelSize / texelsInMap;
|
||||
buf.SetGlobalVector("_ShadowLightWidth", shadowLightWidth);
|
||||
|
||||
buf.SetGlobalFloat("_ShadowBias", m_ShadowBias);
|
||||
}
|
||||
|
||||
void InitMaterial(ref Material material, Shader shader)
|
||||
{
|
||||
if (material)
|
||||
return;
|
||||
|
||||
if (!shader)
|
||||
{
|
||||
Debug.LogError("Missing shader");
|
||||
return;
|
||||
}
|
||||
|
||||
material = new Material(shader);
|
||||
material.hideFlags = HideFlags.HideAndDontSave;
|
||||
}
|
||||
|
||||
void InitShadowmapDummy()
|
||||
{
|
||||
if(m_ShadowmapDummy != null)
|
||||
return;
|
||||
m_ShadowmapDummy = new Texture2D(1, 1, TextureFormat.Alpha8, false, true);
|
||||
m_ShadowmapDummy.filterMode = FilterMode.Point;
|
||||
m_ShadowmapDummy.SetPixel(0, 0, new Color(0f, 0f, 0f, 0f));
|
||||
m_ShadowmapDummy.Apply(false, true);
|
||||
}
|
||||
|
||||
void InitFogLight()
|
||||
{
|
||||
if (m_FogLight != null)
|
||||
return;
|
||||
|
||||
// It should always be here, because it triggered this code path in the first place.
|
||||
m_FogLight = GetComponent<FogLight>();
|
||||
}
|
||||
|
||||
bool InsideShadowmapCameraRender()
|
||||
{
|
||||
RenderTexture target = Camera.current.targetTexture;
|
||||
return target != null && target.format == RenderTextureFormat.Shadowmap;
|
||||
}
|
||||
|
||||
Vector4 GetZParams()
|
||||
{
|
||||
float n = GetNearToCenter();
|
||||
float f = n + m_Size.z;
|
||||
// linear z, 0 near, 1 far
|
||||
// linearz = A * (z + 1.0) / (z + B);
|
||||
// A = n/(n - f)
|
||||
// B = (n + f)/(n - f)
|
||||
|
||||
return new Vector4(n/(n - f), (n + f)/(n - f), 0, 0);
|
||||
}
|
||||
}
|
12
Assets/AreaLight/Scripts/AreaLight.Shadow.cs.meta
Normal file
12
Assets/AreaLight/Scripts/AreaLight.Shadow.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 263b59280b7c4e04aa70d3c9cb1a5586
|
||||
timeCreated: 1455014110
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
297
Assets/AreaLight/Scripts/AreaLight.cs
Normal file
297
Assets/AreaLight/Scripts/AreaLight.cs
Normal file
@ -0,0 +1,297 @@
|
||||
using UnityEngine;
|
||||
|
||||
[ExecuteInEditMode]
|
||||
public partial class AreaLight : MonoBehaviour
|
||||
{
|
||||
public bool m_RenderSource = true;
|
||||
public Vector3 m_Size = new Vector3(1, 1, 2);
|
||||
[Range(0, 179)]
|
||||
public float m_Angle = 0.0f;
|
||||
[MinValue(0)]
|
||||
public float m_Intensity = 0.8f;
|
||||
public Color m_Color = Color.white;
|
||||
|
||||
[Header("Shadows")]
|
||||
public bool m_Shadows = false;
|
||||
public LayerMask m_ShadowCullingMask = ~0;
|
||||
public TextureSize m_ShadowmapRes = TextureSize.x2048;
|
||||
[MinValue(0)]
|
||||
public float m_ReceiverSearchDistance = 24.0f;
|
||||
[MinValue(0)]
|
||||
public float m_ReceiverDistanceScale = 5.0f;
|
||||
[MinValue(0)]
|
||||
public float m_LightNearSize = 4.0f;
|
||||
[MinValue(0)]
|
||||
public float m_LightFarSize = 22.0f;
|
||||
[Range(0, 0.1f)]
|
||||
public float m_ShadowBias = 0.001f;
|
||||
|
||||
MeshRenderer m_SourceRenderer;
|
||||
Mesh m_SourceMesh;
|
||||
[HideInInspector]
|
||||
public Mesh m_Quad;
|
||||
Vector2 m_CurrentQuadSize = Vector2.zero;
|
||||
Vector3 m_CurrentSize = Vector3.zero;
|
||||
float m_CurrentAngle = -1.0f;
|
||||
|
||||
bool m_Initialized = false;
|
||||
MaterialPropertyBlock m_props;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if(!Init())
|
||||
return;
|
||||
UpdateSourceMesh();
|
||||
}
|
||||
|
||||
bool Init()
|
||||
{
|
||||
if (m_Initialized)
|
||||
return true;
|
||||
|
||||
if (m_Quad == null || !InitDirect())
|
||||
return false;
|
||||
|
||||
m_SourceRenderer = GetComponent<MeshRenderer>();
|
||||
m_SourceRenderer.enabled = true;
|
||||
m_SourceMesh = Instantiate<Mesh>(m_Quad);
|
||||
m_SourceMesh.hideFlags = HideFlags.HideAndDontSave;
|
||||
MeshFilter mfs = gameObject.GetComponent<MeshFilter>();
|
||||
mfs.sharedMesh = m_SourceMesh;
|
||||
|
||||
Transform t = transform;
|
||||
if (t.localScale != Vector3.one)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
Debug.LogError("AreaLights don't like to be scaled. Setting local scale to 1.", this);
|
||||
#endif
|
||||
t.localScale = Vector3.one;
|
||||
}
|
||||
|
||||
SetUpLUTs();
|
||||
|
||||
m_Initialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
m_props = new MaterialPropertyBlock();
|
||||
|
||||
if(!Init())
|
||||
return;
|
||||
UpdateSourceMesh();
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
if(!Application.isPlaying)
|
||||
Cleanup();
|
||||
else
|
||||
for(var e = m_Cameras.GetEnumerator(); e.MoveNext();)
|
||||
if(e.Current.Value != null)
|
||||
e.Current.Value.Clear();
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
if (m_ProxyMaterial != null)
|
||||
DestroyImmediate(m_ProxyMaterial);
|
||||
if (m_SourceMesh != null)
|
||||
DestroyImmediate(m_SourceMesh);
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
static Vector3[] vertices = new Vector3[4];
|
||||
|
||||
void UpdateSourceMesh()
|
||||
{
|
||||
m_Size.x = Mathf.Max(m_Size.x, 0);
|
||||
m_Size.y = Mathf.Max(m_Size.y, 0);
|
||||
m_Size.z = Mathf.Max(m_Size.z, 0);
|
||||
|
||||
Vector2 quadSize = m_RenderSource && enabled ? new Vector2(m_Size.x, m_Size.y) : Vector2.one * 0.0001f;
|
||||
if (quadSize != m_CurrentQuadSize)
|
||||
{
|
||||
|
||||
float x = quadSize.x * 0.5f;
|
||||
float y = quadSize.y * 0.5f;
|
||||
// To prevent the source quad from getting into the shadowmap, offset it back a bit.
|
||||
float z = -0.001f;
|
||||
vertices[0].Set(-x, y, z);
|
||||
vertices[1].Set( x, -y, z);
|
||||
vertices[2].Set( x, y, z);
|
||||
vertices[3].Set(-x, -y, z);
|
||||
|
||||
m_SourceMesh.vertices = vertices;
|
||||
|
||||
m_CurrentQuadSize = quadSize;
|
||||
}
|
||||
|
||||
if (m_Size != m_CurrentSize || m_Angle != m_CurrentAngle)
|
||||
{
|
||||
// Set the bounds of the mesh to large, so that they drive rendering of the entire light
|
||||
// TODO: Make the bounds tight around the shape of the light. Right now they're just tight around
|
||||
// the shadow frustum, which is fine if the shadows are enable (ok, maybe far plane should be more clever),
|
||||
// but doesn't make sense if shadows are disabled.
|
||||
m_SourceMesh.bounds = GetFrustumBounds();
|
||||
}
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (!gameObject.activeInHierarchy || !enabled)
|
||||
{
|
||||
Cleanup();
|
||||
return;
|
||||
}
|
||||
|
||||
if(!Init())
|
||||
return;
|
||||
|
||||
UpdateSourceMesh();
|
||||
|
||||
if(Application.isPlaying)
|
||||
for(var e = m_Cameras.GetEnumerator(); e.MoveNext();)
|
||||
if(e.Current.Value != null)
|
||||
e.Current.Value.Clear();
|
||||
}
|
||||
|
||||
void OnWillRenderObject()
|
||||
{
|
||||
if(!Init())
|
||||
return;
|
||||
|
||||
// TODO: This is just a very rough guess. Need to properly calculate the surface emission
|
||||
// intensity based on light's intensity.
|
||||
Color color = new Color(
|
||||
Mathf.GammaToLinearSpace(m_Color.r),
|
||||
Mathf.GammaToLinearSpace(m_Color.g),
|
||||
Mathf.GammaToLinearSpace(m_Color.b),
|
||||
1.0f);
|
||||
m_props.SetVector("_EmissionColor", color * m_Intensity);
|
||||
m_SourceRenderer.SetPropertyBlock(m_props);
|
||||
|
||||
SetUpCommandBuffer();
|
||||
}
|
||||
|
||||
float GetNearToCenter()
|
||||
{
|
||||
if (m_Angle == 0.0f)
|
||||
return 0;
|
||||
|
||||
return m_Size.y * 0.5f / Mathf.Tan(m_Angle * 0.5f * Mathf.Deg2Rad);
|
||||
}
|
||||
|
||||
Matrix4x4 GetOffsetMatrix(float zOffset)
|
||||
{
|
||||
Matrix4x4 m = Matrix4x4.identity;
|
||||
m.SetColumn(3, new Vector4(0, 0, zOffset, 1));
|
||||
return m;
|
||||
}
|
||||
|
||||
public Matrix4x4 GetProjectionMatrix(bool linearZ = false)
|
||||
{
|
||||
Matrix4x4 m;
|
||||
|
||||
if (m_Angle == 0.0f)
|
||||
{
|
||||
m = Matrix4x4.Ortho(-0.5f * m_Size.x, 0.5f * m_Size.x, -0.5f * m_Size.y, 0.5f * m_Size.y, 0, -m_Size.z);
|
||||
}
|
||||
else
|
||||
{
|
||||
float near = GetNearToCenter();
|
||||
if (linearZ)
|
||||
{
|
||||
m = PerspectiveLinearZ(m_Angle, m_Size.x/m_Size.y, near, near + m_Size.z);
|
||||
}
|
||||
else
|
||||
{
|
||||
m = Matrix4x4.Perspective(m_Angle, m_Size.x/m_Size.y, near, near + m_Size.z);
|
||||
m = m * Matrix4x4.Scale(new Vector3(1, 1, -1));
|
||||
}
|
||||
m = m * GetOffsetMatrix(near);
|
||||
}
|
||||
|
||||
return m * transform.worldToLocalMatrix;
|
||||
}
|
||||
|
||||
public Vector4 MultiplyPoint(Matrix4x4 m, Vector3 v)
|
||||
{
|
||||
Vector4 res;
|
||||
res.x = m.m00 * v.x + m.m01 * v.y + m.m02 * v.z + m.m03;
|
||||
res.y = m.m10 * v.x + m.m11 * v.y + m.m12 * v.z + m.m13;
|
||||
res.z = m.m20 * v.x + m.m21 * v.y + m.m22 * v.z + m.m23;
|
||||
res.w = m.m30 * v.x + m.m31 * v.y + m.m32 * v.z + m.m33;
|
||||
return res;
|
||||
}
|
||||
|
||||
Matrix4x4 PerspectiveLinearZ(float fov, float aspect, float near, float far)
|
||||
{
|
||||
// A vector transformed with this matrix should get perspective division on x and y only:
|
||||
// Vector4 vClip = MultiplyPoint(PerspectiveLinearZ(...), vEye);
|
||||
// Vector3 vNDC = Vector3(vClip.x / vClip.w, vClip.y / vClip.w, vClip.z);
|
||||
// vNDC is [-1, 1]^3 and z is linear, i.e. z = 0 is half way between near and far in world space.
|
||||
|
||||
float rad = Mathf.Deg2Rad * fov * 0.5f;
|
||||
float cotan = Mathf.Cos(rad) / Mathf.Sin(rad);
|
||||
float deltainv = 1.0f / (far - near);
|
||||
Matrix4x4 m;
|
||||
|
||||
m.m00 = cotan / aspect; m.m01 = 0.0f; m.m02 = 0.0f; m.m03 = 0.0f;
|
||||
m.m10 = 0.0f; m.m11 = cotan; m.m12 = 0.0f; m.m13 = 0.0f;
|
||||
m.m20 = 0.0f; m.m21 = 0.0f; m.m22 = 2.0f * deltainv; m.m23 = - (far + near) * deltainv;
|
||||
m.m30 = 0.0f; m.m31 = 0.0f; m.m32 = 1.0f; m.m33 = 0.0f;
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
public Vector4 GetPosition()
|
||||
{
|
||||
Transform t = transform;
|
||||
|
||||
if (m_Angle == 0.0f)
|
||||
{
|
||||
Vector3 dir = -t.forward;
|
||||
return new Vector4(dir.x, dir.y, dir.z, 0);
|
||||
}
|
||||
|
||||
Vector3 pos = t.position - GetNearToCenter() * t.forward;
|
||||
return new Vector4(pos.x, pos.y, pos.z, 1);
|
||||
}
|
||||
|
||||
Bounds GetFrustumBounds()
|
||||
{
|
||||
if (m_Angle == 0.0f)
|
||||
return new Bounds(Vector3.zero, m_Size);
|
||||
|
||||
float tanhalffov = Mathf.Tan(m_Angle * 0.5f * Mathf.Deg2Rad);
|
||||
float near = m_Size.y * 0.5f / tanhalffov;
|
||||
float z = m_Size.z;
|
||||
float y = (near + m_Size.z) * tanhalffov * 2.0f;
|
||||
float x = m_Size.x * y / m_Size.y;
|
||||
return new Bounds(Vector3.forward * m_Size.z * 0.5f, new Vector3(x, y, z));
|
||||
}
|
||||
|
||||
void OnDrawGizmosSelected()
|
||||
{
|
||||
Gizmos.color = Color.white;
|
||||
|
||||
if (m_Angle == 0.0f)
|
||||
{
|
||||
Gizmos.matrix = transform.localToWorldMatrix;
|
||||
Gizmos.DrawWireCube(new Vector3(0, 0, 0.5f * m_Size.z), m_Size);
|
||||
return;
|
||||
}
|
||||
|
||||
float near = GetNearToCenter();
|
||||
Gizmos.matrix = transform.localToWorldMatrix * GetOffsetMatrix(-near);
|
||||
|
||||
Gizmos.DrawFrustum(Vector3.zero, m_Angle, near + m_Size.z, near, m_Size.x/m_Size.y);
|
||||
|
||||
Gizmos.matrix = transform.localToWorldMatrix;
|
||||
Gizmos.color = Color.yellow;
|
||||
Bounds bounds = GetFrustumBounds();
|
||||
Gizmos.DrawWireCube(bounds.center, bounds.size);
|
||||
}
|
||||
}
|
16
Assets/AreaLight/Scripts/AreaLight.cs.meta
Normal file
16
Assets/AreaLight/Scripts/AreaLight.cs.meta
Normal file
@ -0,0 +1,16 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 792909cacf2415c48a1d7eebef426b5d
|
||||
timeCreated: 1453121021
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences:
|
||||
- m_Cube: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
|
||||
- m_ProxyShader: {fileID: 4800000, guid: 2b28be3523d190a41910088d1ee68ef7, type: 3}
|
||||
- m_Quad: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0}
|
||||
- m_ShadowmapShader: {fileID: 4800000, guid: 2c4cd42b134f7864fa579350e9cf6896, type: 3}
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8204
Assets/AreaLight/Scripts/AreaLightLUT.DisneyDiffuse.cs
Normal file
8204
Assets/AreaLight/Scripts/AreaLightLUT.DisneyDiffuse.cs
Normal file
File diff suppressed because it is too large
Load Diff
12
Assets/AreaLight/Scripts/AreaLightLUT.DisneyDiffuse.cs.meta
Normal file
12
Assets/AreaLight/Scripts/AreaLightLUT.DisneyDiffuse.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9cbf86f9b2114924a91acc43796a307b
|
||||
timeCreated: 1454419446
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
12304
Assets/AreaLight/Scripts/AreaLightLUT.GGX.cs
Normal file
12304
Assets/AreaLight/Scripts/AreaLightLUT.GGX.cs
Normal file
File diff suppressed because it is too large
Load Diff
12
Assets/AreaLight/Scripts/AreaLightLUT.GGX.cs.meta
Normal file
12
Assets/AreaLight/Scripts/AreaLightLUT.GGX.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2b0041ac2ad0ef8459f7565f64f4d731
|
||||
timeCreated: 1453066169
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
68
Assets/AreaLight/Scripts/AreaLightLUT.Load.cs
Normal file
68
Assets/AreaLight/Scripts/AreaLightLUT.Load.cs
Normal file
@ -0,0 +1,68 @@
|
||||
using UnityEngine;
|
||||
|
||||
public partial class AreaLightLUT
|
||||
{
|
||||
const int kLUTResolution = 64;
|
||||
const int kLUTMatrixDim = 3;
|
||||
|
||||
public enum LUTType
|
||||
{
|
||||
TransformInv_DisneyDiffuse,
|
||||
TransformInv_GGX,
|
||||
AmpDiffAmpSpecFresnel
|
||||
}
|
||||
|
||||
public static Texture2D LoadLUT(LUTType type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case LUTType.TransformInv_DisneyDiffuse: return LoadLUT(s_LUTTransformInv_DisneyDiffuse);
|
||||
case LUTType.TransformInv_GGX: return LoadLUT(s_LUTTransformInv_GGX);
|
||||
case LUTType.AmpDiffAmpSpecFresnel: return LoadLUT(s_LUTAmplitude_DisneyDiffuse, s_LUTAmplitude_GGX, s_LUTFresnel_GGX);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static Texture2D CreateLUT(TextureFormat format, Color[] pixels)
|
||||
{
|
||||
Texture2D tex = new Texture2D(kLUTResolution, kLUTResolution, format, false /*mipmap*/, true /*linear*/);
|
||||
tex.hideFlags = HideFlags.HideAndDontSave;
|
||||
tex.wrapMode = TextureWrapMode.Clamp;
|
||||
tex.SetPixels(pixels);
|
||||
tex.Apply();
|
||||
return tex;
|
||||
}
|
||||
|
||||
static Texture2D LoadLUT(double[,] LUTTransformInv)
|
||||
{
|
||||
const int count = kLUTResolution * kLUTResolution;
|
||||
Color[] pixels = new Color[count];
|
||||
|
||||
// transformInv
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
// Only columns 0, 2, 4 and 6 contain interesting values (at least in the case of GGX).
|
||||
pixels[i] = new Color( (float)LUTTransformInv[i, 0],
|
||||
(float)LUTTransformInv[i, 2],
|
||||
(float)LUTTransformInv[i, 4],
|
||||
(float)LUTTransformInv[i, 6]);
|
||||
}
|
||||
|
||||
return CreateLUT(TextureFormat.RGBAHalf, pixels);
|
||||
}
|
||||
|
||||
static Texture2D LoadLUT(float[] LUTScalar0, float[] LUTScalar1, float[] LUTScalar2)
|
||||
{
|
||||
const int count = kLUTResolution * kLUTResolution;
|
||||
Color[] pixels = new Color[count];
|
||||
|
||||
// amplitude
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
pixels[i] = new Color(LUTScalar0[i], LUTScalar1[i], LUTScalar2[i], 0);
|
||||
}
|
||||
|
||||
return CreateLUT(TextureFormat.RGBAHalf, pixels);
|
||||
}
|
||||
}
|
12
Assets/AreaLight/Scripts/AreaLightLUT.Load.cs.meta
Normal file
12
Assets/AreaLight/Scripts/AreaLightLUT.Load.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0c08d6c4951e30c42a4bd6209323dfb8
|
||||
timeCreated: 1453070529
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
9
Assets/AreaLight/Shaders.meta
Normal file
9
Assets/AreaLight/Shaders.meta
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d622c47de56b9e84e971b5a72b861f95
|
||||
folderAsset: yes
|
||||
timeCreated: 1477749207
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
224
Assets/AreaLight/Shaders/AreaLight.cginc
Normal file
224
Assets/AreaLight/Shaders/AreaLight.cginc
Normal file
@ -0,0 +1,224 @@
|
||||
// Based on 'Real-Time Polygonal-Light Shading with Linearly Transformed Cosines'
|
||||
// https://labs.unity.com/article/real-time-polygonal-light-shading-linearly-transformed-cosines
|
||||
|
||||
#if AREA_LIGHT_ENABLE_DIFFUSE
|
||||
sampler2D _TransformInv_Diffuse;
|
||||
#endif
|
||||
sampler2D _TransformInv_Specular;
|
||||
sampler2D _AmpDiffAmpSpecFresnel;
|
||||
float4x4 _LightVerts;
|
||||
|
||||
half IntegrateEdge(half3 v1, half3 v2)
|
||||
{
|
||||
half d = dot(v1,v2);
|
||||
half theta = acos(max(-0.9999, dot(v1,v2)));
|
||||
half theta_sintheta = theta / sin(theta);
|
||||
return theta_sintheta * (v1.x*v2.y - v1.y*v2.x);
|
||||
}
|
||||
|
||||
// Baum's equation
|
||||
// Expects non-normalized vertex positions
|
||||
half PolygonRadiance(half4x3 L)
|
||||
{
|
||||
// detect clipping config
|
||||
uint config = 0;
|
||||
if (L[0].z > 0) config += 1;
|
||||
if (L[1].z > 0) config += 2;
|
||||
if (L[2].z > 0) config += 4;
|
||||
if (L[3].z > 0) config += 8;
|
||||
|
||||
|
||||
// The fifth vertex for cases when clipping cuts off one corner.
|
||||
// Due to a compiler bug, copying L into a vector array with 5 rows
|
||||
// messes something up, so we need to stick with the matrix + the L4 vertex.
|
||||
half3 L4 = L[3];
|
||||
|
||||
// This switch is surprisingly fast. Tried replacing it with a lookup array of vertices.
|
||||
// Even though that replaced the switch with just some indexing and no branches, it became
|
||||
// way, way slower - mem fetch stalls?
|
||||
|
||||
// clip
|
||||
uint n = 0;
|
||||
switch(config)
|
||||
{
|
||||
case 0: // clip all
|
||||
break;
|
||||
|
||||
case 1: // V1 clip V2 V3 V4
|
||||
n = 3;
|
||||
L[1] = -L[1].z * L[0] + L[0].z * L[1];
|
||||
L[2] = -L[3].z * L[0] + L[0].z * L[3];
|
||||
break;
|
||||
|
||||
case 2: // V2 clip V1 V3 V4
|
||||
n = 3;
|
||||
L[0] = -L[0].z * L[1] + L[1].z * L[0];
|
||||
L[2] = -L[2].z * L[1] + L[1].z * L[2];
|
||||
break;
|
||||
|
||||
case 3: // V1 V2 clip V3 V4
|
||||
n = 4;
|
||||
L[2] = -L[2].z * L[1] + L[1].z * L[2];
|
||||
L[3] = -L[3].z * L[0] + L[0].z * L[3];
|
||||
break;
|
||||
|
||||
case 4: // V3 clip V1 V2 V4
|
||||
n = 3;
|
||||
L[0] = -L[3].z * L[2] + L[2].z * L[3];
|
||||
L[1] = -L[1].z * L[2] + L[2].z * L[1];
|
||||
break;
|
||||
|
||||
case 5: // V1 V3 clip V2 V4: impossible
|
||||
break;
|
||||
|
||||
case 6: // V2 V3 clip V1 V4
|
||||
n = 4;
|
||||
L[0] = -L[0].z * L[1] + L[1].z * L[0];
|
||||
L[3] = -L[3].z * L[2] + L[2].z * L[3];
|
||||
break;
|
||||
|
||||
case 7: // V1 V2 V3 clip V4
|
||||
n = 5;
|
||||
L4 = -L[3].z * L[0] + L[0].z * L[3];
|
||||
L[3] = -L[3].z * L[2] + L[2].z * L[3];
|
||||
break;
|
||||
|
||||
case 8: // V4 clip V1 V2 V3
|
||||
n = 3;
|
||||
L[0] = -L[0].z * L[3] + L[3].z * L[0];
|
||||
L[1] = -L[2].z * L[3] + L[3].z * L[2];
|
||||
L[2] = L[3];
|
||||
break;
|
||||
|
||||
case 9: // V1 V4 clip V2 V3
|
||||
n = 4;
|
||||
L[1] = -L[1].z * L[0] + L[0].z * L[1];
|
||||
L[2] = -L[2].z * L[3] + L[3].z * L[2];
|
||||
break;
|
||||
|
||||
case 10: // V2 V4 clip V1 V3: impossible
|
||||
break;
|
||||
|
||||
case 11: // V1 V2 V4 clip V3
|
||||
n = 5;
|
||||
L[3] = -L[2].z * L[3] + L[3].z * L[2];
|
||||
L[2] = -L[2].z * L[1] + L[1].z * L[2];
|
||||
break;
|
||||
|
||||
case 12: // V3 V4 clip V1 V2
|
||||
n = 4;
|
||||
L[1] = -L[1].z * L[2] + L[2].z * L[1];
|
||||
L[0] = -L[0].z * L[3] + L[3].z * L[0];
|
||||
break;
|
||||
|
||||
case 13: // V1 V3 V4 clip V2
|
||||
n = 5;
|
||||
L[3] = L[2];
|
||||
L[2] = -L[1].z * L[2] + L[2].z * L[1];
|
||||
L[1] = -L[1].z * L[0] + L[0].z * L[1];
|
||||
break;
|
||||
|
||||
case 14: // V2 V3 V4 clip V1
|
||||
n = 5;
|
||||
L4 = -L[0].z * L[3] + L[3].z * L[0];
|
||||
L[0] = -L[0].z * L[1] + L[1].z * L[0];
|
||||
break;
|
||||
|
||||
case 15: // V1 V2 V3 V4
|
||||
n = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
if (n == 0)
|
||||
return 0;
|
||||
|
||||
// normalize
|
||||
L[0] = normalize(L[0]);
|
||||
L[1] = normalize(L[1]);
|
||||
L[2] = normalize(L[2]);
|
||||
if(n == 3)
|
||||
L[3] = L[0];
|
||||
else
|
||||
{
|
||||
L[3] = normalize(L[3]);
|
||||
if (n == 4)
|
||||
L4 = L[0];
|
||||
else
|
||||
L4 = normalize(L4);
|
||||
}
|
||||
|
||||
// integrate
|
||||
half sum = 0;
|
||||
sum += IntegrateEdge(L[0], L[1]);
|
||||
sum += IntegrateEdge(L[1], L[2]);
|
||||
sum += IntegrateEdge(L[2], L[3]);
|
||||
if(n >= 4)
|
||||
sum += IntegrateEdge(L[3], L4);
|
||||
if(n == 5)
|
||||
sum += IntegrateEdge(L4, L[0]);
|
||||
|
||||
sum *= 0.15915; // 1/2pi
|
||||
|
||||
return max(0, sum);
|
||||
}
|
||||
|
||||
half TransformedPolygonRadiance(half4x3 L, half2 uv, sampler2D transformInv, half amplitude)
|
||||
{
|
||||
// Get the inverse LTC matrix M
|
||||
half3x3 Minv = 0;
|
||||
Minv._m22 = 1;
|
||||
Minv._m00_m02_m11_m20 = tex2D(transformInv, uv);
|
||||
|
||||
// Transform light vertices into diffuse configuration
|
||||
half4x3 LTransformed = mul(L, Minv);
|
||||
|
||||
// Polygon radiance in transformed configuration - specular
|
||||
return PolygonRadiance(LTransformed) * amplitude;
|
||||
}
|
||||
|
||||
half3 CalculateLight (half3 position, half3 diffColor, half3 specColor, half oneMinusRoughness, half3 N,
|
||||
half3 lightPos, half3 lightColor)
|
||||
{
|
||||
#if AREA_LIGHT_SHADOWS
|
||||
half shadow = Shadow(position);
|
||||
if (shadow == 0.0)
|
||||
return 0;
|
||||
#endif
|
||||
// TODO: larger and smaller values cause artifacts - why?
|
||||
oneMinusRoughness = clamp(oneMinusRoughness, 0.01, 0.93);
|
||||
half roughness = 1 - oneMinusRoughness;
|
||||
half3 V = normalize(_WorldSpaceCameraPos - position);
|
||||
|
||||
// Construct orthonormal basis around N, aligned with V
|
||||
half3x3 basis;
|
||||
basis[0] = normalize(V - N * dot(V, N));
|
||||
basis[1] = normalize(cross(N, basis[0]));
|
||||
basis[2] = N;
|
||||
|
||||
// Transform light vertices into that space
|
||||
half4x3 L;
|
||||
L = _LightVerts - half4x3(position, position, position, position);
|
||||
L = mul(L, transpose(basis));
|
||||
|
||||
// UVs for sampling the LUTs
|
||||
half theta = acos(dot(V, N));
|
||||
half2 uv = half2(roughness, theta/1.57);
|
||||
|
||||
half3 AmpDiffAmpSpecFresnel = tex2D(_AmpDiffAmpSpecFresnel, uv).rgb;
|
||||
|
||||
half3 result = 0;
|
||||
#if AREA_LIGHT_ENABLE_DIFFUSE
|
||||
half diffuseTerm = TransformedPolygonRadiance(L, uv, _TransformInv_Diffuse, AmpDiffAmpSpecFresnel.x);
|
||||
result = diffuseTerm * diffColor;
|
||||
#endif
|
||||
|
||||
half specularTerm = TransformedPolygonRadiance(L, uv, _TransformInv_Specular, AmpDiffAmpSpecFresnel.y);
|
||||
half fresnelTerm = specColor + (1.0 - specColor) * AmpDiffAmpSpecFresnel.z;
|
||||
result += specularTerm * fresnelTerm * UNITY_PI;
|
||||
|
||||
#if AREA_LIGHT_SHADOWS
|
||||
result *= shadow;
|
||||
#endif
|
||||
|
||||
return result * lightColor;
|
||||
}
|
9
Assets/AreaLight/Shaders/AreaLight.cginc.meta
Normal file
9
Assets/AreaLight/Shaders/AreaLight.cginc.meta
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fd7e771f2b4bdf14da1d4e099b8bd629
|
||||
timeCreated: 1453121090
|
||||
licenseType: Pro
|
||||
ShaderImporter:
|
||||
defaultTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
110
Assets/AreaLight/Shaders/AreaLight.shader
Normal file
110
Assets/AreaLight/Shaders/AreaLight.shader
Normal file
@ -0,0 +1,110 @@
|
||||
Shader "Hidden/AreaLight" {
|
||||
SubShader {
|
||||
Tags { "Queue"="Geometry-1" }
|
||||
|
||||
CGINCLUDE
|
||||
#include "UnityCG.cginc"
|
||||
#include "UnityPBSLighting.cginc"
|
||||
#include "UnityDeferredLibrary.cginc"
|
||||
|
||||
#define AREA_LIGHT_ENABLE_DIFFUSE 1
|
||||
|
||||
#if AREA_LIGHT_SHADOWS
|
||||
#include "AreaLightShadows.cginc"
|
||||
#endif
|
||||
#include "AreaLight.cginc"
|
||||
|
||||
sampler2D _CameraGBufferTexture0;
|
||||
sampler2D _CameraGBufferTexture1;
|
||||
sampler2D _CameraGBufferTexture2;
|
||||
|
||||
void DeferredCalculateLightParams (
|
||||
unity_v2f_deferred i,
|
||||
out float3 outWorldPos,
|
||||
out float2 outUV)
|
||||
{
|
||||
i.ray = i.ray * (_ProjectionParams.z / i.ray.z);
|
||||
float2 uv = i.uv.xy / i.uv.w;
|
||||
|
||||
// read depth and reconstruct world position
|
||||
float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv);
|
||||
depth = Linear01Depth (depth);
|
||||
float4 vpos = float4(i.ray * depth,1);
|
||||
float3 wpos = mul (unity_CameraToWorld, vpos).xyz;
|
||||
|
||||
outWorldPos = wpos;
|
||||
outUV = uv;
|
||||
}
|
||||
|
||||
half4 CalculateLightDeferred (unity_v2f_deferred i)
|
||||
{
|
||||
float3 worldPos;
|
||||
float2 uv;
|
||||
DeferredCalculateLightParams (i, worldPos, uv);
|
||||
|
||||
half4 gbuffer0 = tex2D (_CameraGBufferTexture0, uv);
|
||||
half4 gbuffer1 = tex2D (_CameraGBufferTexture1, uv);
|
||||
half4 gbuffer2 = tex2D (_CameraGBufferTexture2, uv);
|
||||
|
||||
half3 baseColor = gbuffer0.rgb;
|
||||
half3 specColor = gbuffer1.rgb;
|
||||
half oneMinusRoughness = gbuffer1.a;
|
||||
half3 normalWorld = gbuffer2.rgb * 2 - 1;
|
||||
normalWorld = normalize(normalWorld);
|
||||
|
||||
return CalculateLight (worldPos, baseColor, specColor, oneMinusRoughness, normalWorld,
|
||||
_LightPos.xyz, _LightColor.xyz).rgbb;
|
||||
}
|
||||
ENDCG
|
||||
|
||||
// shadows
|
||||
Pass
|
||||
{
|
||||
Fog { Mode Off }
|
||||
ZWrite Off
|
||||
Blend One One
|
||||
Cull Front
|
||||
ZTest Always
|
||||
|
||||
CGPROGRAM
|
||||
#pragma target 3.0
|
||||
#pragma vertex vert_deferred
|
||||
#pragma fragment frag
|
||||
#pragma exclude_renderers nomrt
|
||||
// only one option, so it will always be set and before any includes
|
||||
#pragma multi_compile AREA_LIGHT_SHADOWS
|
||||
|
||||
fixed4 frag (unity_v2f_deferred i) : SV_Target
|
||||
{
|
||||
return CalculateLightDeferred(i);
|
||||
}
|
||||
|
||||
ENDCG
|
||||
}
|
||||
|
||||
// no shadows
|
||||
Pass
|
||||
{
|
||||
Fog { Mode Off }
|
||||
ZWrite Off
|
||||
Blend One One
|
||||
Cull Front
|
||||
ZTest Always
|
||||
|
||||
CGPROGRAM
|
||||
#pragma target 3.0
|
||||
#pragma vertex vert_deferred
|
||||
#pragma fragment frag
|
||||
#pragma exclude_renderers nomrt
|
||||
|
||||
fixed4 frag (unity_v2f_deferred i) : SV_Target
|
||||
{
|
||||
return CalculateLightDeferred(i);
|
||||
}
|
||||
|
||||
ENDCG
|
||||
}
|
||||
|
||||
}
|
||||
Fallback Off
|
||||
}
|
9
Assets/AreaLight/Shaders/AreaLight.shader.meta
Normal file
9
Assets/AreaLight/Shaders/AreaLight.shader.meta
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2b28be3523d190a41910088d1ee68ef7
|
||||
timeCreated: 1453120999
|
||||
licenseType: Pro
|
||||
ShaderImporter:
|
||||
defaultTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
103
Assets/AreaLight/Shaders/AreaLightShadows.cginc
Normal file
103
Assets/AreaLight/Shaders/AreaLightShadows.cginc
Normal file
@ -0,0 +1,103 @@
|
||||
cbuffer POISSON_DISKS {
|
||||
static half2 poisson[40] = {
|
||||
half2(0.02971195f, 0.8905211f),
|
||||
half2(0.2495298f, 0.732075f),
|
||||
half2(-0.3469206f, 0.6437836f),
|
||||
half2(-0.01878909f, 0.4827394f),
|
||||
half2(-0.2725213f, 0.896188f),
|
||||
half2(-0.6814336f, 0.6480481f),
|
||||
half2(0.4152045f, 0.2794172f),
|
||||
half2(0.1310554f, 0.2675925f),
|
||||
half2(0.5344744f, 0.5624411f),
|
||||
half2(0.8385689f, 0.5137348f),
|
||||
half2(0.6045052f, 0.08393857f),
|
||||
half2(0.4643163f, 0.8684642f),
|
||||
half2(0.335507f, -0.110113f),
|
||||
half2(0.03007669f, -0.0007075319f),
|
||||
half2(0.8077537f, 0.2551664f),
|
||||
half2(-0.1521498f, 0.2429521f),
|
||||
half2(-0.2997617f, 0.0234927f),
|
||||
half2(0.2587779f, -0.4226915f),
|
||||
half2(-0.01448214f, -0.2720358f),
|
||||
half2(-0.3937779f, -0.228529f),
|
||||
half2(-0.7833176f, 0.1737299f),
|
||||
half2(-0.4447537f, 0.2582748f),
|
||||
half2(-0.9030743f, 0.406874f),
|
||||
half2(-0.729588f, -0.2115215f),
|
||||
half2(-0.5383645f, -0.6681151f),
|
||||
half2(-0.07709587f, -0.5395499f),
|
||||
half2(-0.3402214f, -0.4782109f),
|
||||
half2(-0.5580465f, 0.01399586f),
|
||||
half2(-0.105644f, -0.9191031f),
|
||||
half2(-0.8343651f, -0.4750755f),
|
||||
half2(-0.9959937f, -0.0540134f),
|
||||
half2(0.1747736f, -0.936202f),
|
||||
half2(-0.3642297f, -0.926432f),
|
||||
half2(0.1719682f, -0.6798802f),
|
||||
half2(0.4424475f, -0.7744268f),
|
||||
half2(0.6849481f, -0.3031401f),
|
||||
half2(0.5453879f, -0.5152272f),
|
||||
half2(0.9634013f, -0.2050581f),
|
||||
half2(0.9907925f, 0.08320642f),
|
||||
half2(0.8386722f, -0.5428791f)
|
||||
};
|
||||
};
|
||||
|
||||
Texture2D _Shadowmap;
|
||||
SamplerComparisonState sampler_Shadowmap;
|
||||
|
||||
// To get a sampler, which doesn't do comparison
|
||||
Texture2D _ShadowmapDummy;
|
||||
SamplerState sampler_ShadowmapDummy;
|
||||
|
||||
half _ShadowReceiverWidth;
|
||||
half _ShadowReceiverDistanceScale;
|
||||
half2 _ShadowLightWidth;
|
||||
half _ShadowBias;
|
||||
float4x4 _ShadowProjectionMatrix;
|
||||
|
||||
half EdgeSmooth(half2 xy)
|
||||
{
|
||||
// Magic tweaks to the shape
|
||||
float corner = 0.4;
|
||||
float outset = 1.0;
|
||||
float smooth = 0.5;
|
||||
|
||||
float d = length(max(abs(xy) - 1 + corner*outset, 0.0)) - corner;
|
||||
return saturate(1 - smoothstep(-smooth, 0, d));
|
||||
}
|
||||
|
||||
half Shadow(half3 position)
|
||||
{
|
||||
half4 pClip = mul(_ShadowProjectionMatrix, half4(position, 1));
|
||||
half3 p = pClip.xyz/pClip.w;
|
||||
if (any(step(1.0, abs(p.xy))))
|
||||
return 0;
|
||||
|
||||
// The texture contains just 0. But we need to sample it somewhere for Unity to initialize the corresponding sampler.
|
||||
float dist = _ShadowmapDummy.Sample(sampler_ShadowmapDummy, 0).a;
|
||||
|
||||
half edgeSmooth = EdgeSmooth(p.xy);
|
||||
p = p * 0.5 + 0.5;
|
||||
|
||||
for(int j = 0; j < 10; ++j)
|
||||
{
|
||||
half2 offset = poisson[j + 24] * _ShadowReceiverWidth;
|
||||
float depth = _Shadowmap.SampleLevel(sampler_ShadowmapDummy, p.xy + offset, 0).r;
|
||||
|
||||
dist += max(0.0, p.z - depth);
|
||||
}
|
||||
|
||||
dist *= _ShadowReceiverDistanceScale;
|
||||
|
||||
p.z -= _ShadowBias/pClip.w;
|
||||
half shadow = 0;
|
||||
for(int i = 0; i < 32; ++i)
|
||||
{
|
||||
half lightWidth = lerp(_ShadowLightWidth.x, _ShadowLightWidth.y, min(1.0, dist));
|
||||
const half2 offset = poisson[i] * lightWidth;
|
||||
shadow += _Shadowmap.SampleCmpLevelZero(sampler_Shadowmap, p.xy + offset, p.z);
|
||||
}
|
||||
|
||||
return shadow * edgeSmooth / 32.0;
|
||||
}
|
9
Assets/AreaLight/Shaders/AreaLightShadows.cginc.meta
Normal file
9
Assets/AreaLight/Shaders/AreaLightShadows.cginc.meta
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eeb2994f509cea043bc495c62bc72a29
|
||||
timeCreated: 1456842264
|
||||
licenseType: Pro
|
||||
ShaderImporter:
|
||||
defaultTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
184
Assets/AreaLight/Shaders/AreaLightSource.mat
Normal file
184
Assets/AreaLight/Shaders/AreaLightSource.mat
Normal file
@ -0,0 +1,184 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 0}
|
||||
m_Name: AreaLightSource
|
||||
m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_ShaderKeywords: _EMISSION
|
||||
m_LightmapFlags: 1
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap: {}
|
||||
m_SavedProperties:
|
||||
serializedVersion: 2
|
||||
m_TexEnvs:
|
||||
- first:
|
||||
name: _BumpMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- first:
|
||||
name: _DetailAlbedoMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- first:
|
||||
name: _DetailMask
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- first:
|
||||
name: _DetailNormalMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- first:
|
||||
name: _EmissionMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- first:
|
||||
name: _MainTex
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- first:
|
||||
name: _MetallicGlossMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- first:
|
||||
name: _OcclusionMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- first:
|
||||
name: _ParallaxMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- first:
|
||||
name: _SpecGlossMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Floats:
|
||||
- first:
|
||||
name: _BumpScale
|
||||
second: 1
|
||||
- first:
|
||||
name: _CullMode
|
||||
second: 2
|
||||
- first:
|
||||
name: _Cutoff
|
||||
second: 0.5
|
||||
- first:
|
||||
name: _DetailMode
|
||||
second: 0
|
||||
- first:
|
||||
name: _DetailNormalMapScale
|
||||
second: 1
|
||||
- first:
|
||||
name: _DstBlend
|
||||
second: 0
|
||||
- first:
|
||||
name: _GlossMapScale
|
||||
second: 1
|
||||
- first:
|
||||
name: _Glossiness
|
||||
second: 0
|
||||
- first:
|
||||
name: _GlossyReflections
|
||||
second: 1
|
||||
- first:
|
||||
name: _MetaDiffuseScale
|
||||
second: 1
|
||||
- first:
|
||||
name: _MetaEmissionScale
|
||||
second: 1
|
||||
- first:
|
||||
name: _MetaMetallicSoup
|
||||
second: 1
|
||||
- first:
|
||||
name: _MetaSpecularScale
|
||||
second: 1
|
||||
- first:
|
||||
name: _MetaUseCustom
|
||||
second: 0
|
||||
- first:
|
||||
name: _Metallic
|
||||
second: 0
|
||||
- first:
|
||||
name: _Mode
|
||||
second: 0
|
||||
- first:
|
||||
name: _OcclusionStrength
|
||||
second: 1
|
||||
- first:
|
||||
name: _Parallax
|
||||
second: 0.02
|
||||
- first:
|
||||
name: _SmoothnessTextureChannel
|
||||
second: 0
|
||||
- first:
|
||||
name: _SpecularHighlights
|
||||
second: 1
|
||||
- first:
|
||||
name: _SrcBlend
|
||||
second: 1
|
||||
- first:
|
||||
name: _Translucency
|
||||
second: 0
|
||||
- first:
|
||||
name: _UVDetailMask
|
||||
second: 0
|
||||
- first:
|
||||
name: _UVSec
|
||||
second: 0
|
||||
- first:
|
||||
name: _VertexOcclusionPower
|
||||
second: 1
|
||||
- first:
|
||||
name: _ZWrite
|
||||
second: 1
|
||||
m_Colors:
|
||||
- first:
|
||||
name: _Color
|
||||
second: {r: 0, g: 0, b: 0, a: 1}
|
||||
- first:
|
||||
name: _EmissionColor
|
||||
second: {r: 1, g: 1, b: 1, a: 1}
|
||||
- first:
|
||||
name: _MetaDiffuseAdd
|
||||
second: {r: 0, g: 0, b: 0, a: 1}
|
||||
- first:
|
||||
name: _MetaDiffuseTint
|
||||
second: {r: 1, g: 1, b: 1, a: 1}
|
||||
- first:
|
||||
name: _MetaEmissionAdd
|
||||
second: {r: 0, g: 0, b: 0, a: 1}
|
||||
- first:
|
||||
name: _MetaEmissionTint
|
||||
second: {r: 1, g: 1, b: 1, a: 1}
|
||||
- first:
|
||||
name: _MetaSpecularAdd
|
||||
second: {r: 0, g: 0, b: 0, a: 1}
|
||||
- first:
|
||||
name: _MetaSpecularTint
|
||||
second: {r: 1, g: 1, b: 1, a: 1}
|
||||
- first:
|
||||
name: _SpecColor
|
||||
second: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
|
8
Assets/AreaLight/Shaders/AreaLightSource.mat.meta
Normal file
8
Assets/AreaLight/Shaders/AreaLightSource.mat.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1eb056d70e23cc34a9e926d8c8c887a5
|
||||
timeCreated: 1450296949
|
||||
licenseType: Pro
|
||||
NativeFormatImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
9
Assets/LightManager.meta
Normal file
9
Assets/LightManager.meta
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 37a7d2078af3b7645802711b72cbcfb1
|
||||
folderAsset: yes
|
||||
timeCreated: 1477430433
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
52
Assets/LightManager/LightManagerFogEllipsoids.prefab
Normal file
52
Assets/LightManager/LightManagerFogEllipsoids.prefab
Normal file
@ -0,0 +1,52 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1001 &100100000
|
||||
Prefab:
|
||||
m_ObjectHideFlags: 1
|
||||
serializedVersion: 2
|
||||
m_Modification:
|
||||
m_TransformParent: {fileID: 0}
|
||||
m_Modifications: []
|
||||
m_RemovedComponents: []
|
||||
m_ParentPrefab: {fileID: 0}
|
||||
m_RootGameObject: {fileID: 1000010085349158}
|
||||
m_IsPrefabParent: 1
|
||||
--- !u!1 &1000010085349158
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
serializedVersion: 4
|
||||
m_Component:
|
||||
- 4: {fileID: 4000010739719174}
|
||||
- 114: {fileID: 114000014191307454}
|
||||
m_Layer: 0
|
||||
m_Name: LightManagerFogEllipsoids
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &4000010739719174
|
||||
Transform:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1000010085349158}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: -8.9284725, y: 3.427047, z: -0.21317804}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
--- !u!114 &114000014191307454
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1000010085349158}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: ed243fe90a2e7384f9f6f59acf71e19b, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 88ddc3de348eb9044aa7d0614809939e
|
||||
timeCreated: 1454679592
|
||||
licenseType: Pro
|
||||
NativeFormatImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
52
Assets/LightManager/LightManagerFogLights.prefab
Normal file
52
Assets/LightManager/LightManagerFogLights.prefab
Normal file
@ -0,0 +1,52 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1001 &100100000
|
||||
Prefab:
|
||||
m_ObjectHideFlags: 1
|
||||
serializedVersion: 2
|
||||
m_Modification:
|
||||
m_TransformParent: {fileID: 0}
|
||||
m_Modifications: []
|
||||
m_RemovedComponents: []
|
||||
m_ParentPrefab: {fileID: 0}
|
||||
m_RootGameObject: {fileID: 1000011378053400}
|
||||
m_IsPrefabParent: 1
|
||||
--- !u!1 &1000011378053400
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
serializedVersion: 4
|
||||
m_Component:
|
||||
- 4: {fileID: 4000012687929690}
|
||||
- 114: {fileID: 114000010476117714}
|
||||
m_Layer: 0
|
||||
m_Name: LightManagerFogLights
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &4000012687929690
|
||||
Transform:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1000011378053400}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: -8.9284725, y: 3.427047, z: -0.21317804}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
--- !u!114 &114000010476117714
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1000011378053400}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 01ae89c4c08f92f4fb90537335efa1ac, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
8
Assets/LightManager/LightManagerFogLights.prefab.meta
Normal file
8
Assets/LightManager/LightManagerFogLights.prefab.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a81286e4a5a12aa41825352231edaae9
|
||||
timeCreated: 1454679202
|
||||
licenseType: Pro
|
||||
NativeFormatImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
9
Assets/LightManager/Scripts.meta
Normal file
9
Assets/LightManager/Scripts.meta
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: de005349eca348945bb8d27456a32d16
|
||||
folderAsset: yes
|
||||
timeCreated: 1477748682
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
45
Assets/LightManager/Scripts/LightManager.cs
Normal file
45
Assets/LightManager/Scripts/LightManager.cs
Normal file
@ -0,0 +1,45 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class LightManager<T> : MonoBehaviour
|
||||
{
|
||||
static LightManager<T> s_Instance;
|
||||
HashSet<T> m_Container = new HashSet<T>();
|
||||
|
||||
static LightManager<T> Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (s_Instance != null)
|
||||
return s_Instance;
|
||||
|
||||
s_Instance = (LightManager<T>) FindObjectOfType(typeof(LightManager<T>));
|
||||
return s_Instance;
|
||||
}
|
||||
}
|
||||
|
||||
public static HashSet<T> Get()
|
||||
{
|
||||
LightManager<T> instance = Instance;
|
||||
return instance == null ? new HashSet<T>() : instance.m_Container;
|
||||
}
|
||||
|
||||
public static bool Add(T t)
|
||||
{
|
||||
LightManager<T> instance = Instance;
|
||||
if (instance == null)
|
||||
return false;
|
||||
|
||||
instance.m_Container.Add(t);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void Remove(T t)
|
||||
{
|
||||
LightManager<T> instance = Instance;
|
||||
if (instance == null)
|
||||
return;
|
||||
|
||||
instance.m_Container.Remove(t);
|
||||
}
|
||||
}
|
12
Assets/LightManager/Scripts/LightManager.cs.meta
Normal file
12
Assets/LightManager/Scripts/LightManager.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 172fcfd4ae7b9874ea684dc927b34a73
|
||||
timeCreated: 1454671716
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
4
Assets/LightManager/Scripts/LightManagerFogEllipsoids.cs
Normal file
4
Assets/LightManager/Scripts/LightManagerFogEllipsoids.cs
Normal file
@ -0,0 +1,4 @@
|
||||
public class LightManagerFogEllipsoids : LightManager<FogEllipsoid>
|
||||
{
|
||||
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ed243fe90a2e7384f9f6f59acf71e19b
|
||||
timeCreated: 1454679513
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
4
Assets/LightManager/Scripts/LightManagerFogLights.cs
Normal file
4
Assets/LightManager/Scripts/LightManagerFogLights.cs
Normal file
@ -0,0 +1,4 @@
|
||||
public class LightManagerFogLights : LightManager<FogLight>
|
||||
{
|
||||
|
||||
}
|
12
Assets/LightManager/Scripts/LightManagerFogLights.cs.meta
Normal file
12
Assets/LightManager/Scripts/LightManagerFogLights.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 01ae89c4c08f92f4fb90537335efa1ac
|
||||
timeCreated: 1454678969
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
9
Assets/LightOverride.meta
Normal file
9
Assets/LightOverride.meta
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d10a5eee313f53847b6aed96428c054d
|
||||
folderAsset: yes
|
||||
timeCreated: 1477430433
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
81
Assets/LightOverride/LightOverride.cs
Normal file
81
Assets/LightOverride/LightOverride.cs
Normal file
@ -0,0 +1,81 @@
|
||||
using UnityEngine;
|
||||
|
||||
public abstract class LightOverride : MonoBehaviour
|
||||
{
|
||||
|
||||
[Header("Overrides")]
|
||||
public float m_IntensityMult = 1.0f;
|
||||
[MinValue(0.0f)]
|
||||
public float m_RangeMult = 1.0f;
|
||||
|
||||
public enum Type{None, Point, Tube, Area, Directional}
|
||||
|
||||
Type m_Type = Type.None;
|
||||
bool m_Initialized = false;
|
||||
Light m_Light;
|
||||
TubeLight m_TubeLight;
|
||||
AreaLight m_AreaLight;
|
||||
|
||||
public bool isOn
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!isActiveAndEnabled)
|
||||
return false;
|
||||
|
||||
Init();
|
||||
|
||||
switch(m_Type)
|
||||
{
|
||||
case Type.Point: return m_Light.enabled || GetForceOn();
|
||||
case Type.Tube: return m_TubeLight.enabled || GetForceOn();
|
||||
case Type.Area: return m_AreaLight.enabled || GetForceOn();
|
||||
case Type.Directional: return m_Light.enabled || GetForceOn();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private set{}
|
||||
}
|
||||
|
||||
new public Light light {get{Init(); return m_Light;} private set{}}
|
||||
public TubeLight tubeLight {get{Init(); return m_TubeLight;} private set{}}
|
||||
public AreaLight areaLight {get{Init(); return m_AreaLight;} private set{}}
|
||||
|
||||
public Type type {get{Init(); return m_Type;} private set{}}
|
||||
|
||||
// To get the "enabled" state checkbox
|
||||
void Update()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public abstract bool GetForceOn();
|
||||
|
||||
void Init()
|
||||
{
|
||||
if (m_Initialized)
|
||||
return;
|
||||
|
||||
if ((m_Light = GetComponent<Light>()) != null)
|
||||
{
|
||||
switch(m_Light.type)
|
||||
{
|
||||
case LightType.Point: m_Type = Type.Point; break;
|
||||
case LightType.Directional: m_Type = Type.Directional; break;
|
||||
default: m_Type = Type.None; break;
|
||||
}
|
||||
}
|
||||
else if ((m_TubeLight = GetComponent<TubeLight>()) != null)
|
||||
{
|
||||
m_Type = Type.Tube;
|
||||
}
|
||||
else if ((m_AreaLight = GetComponent<AreaLight>()) != null)
|
||||
{
|
||||
m_Type = Type.Area;
|
||||
}
|
||||
|
||||
m_Initialized = true;
|
||||
}
|
||||
}
|
12
Assets/LightOverride/LightOverride.cs.meta
Normal file
12
Assets/LightOverride/LightOverride.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 74f38ff2229b3664e979e3a59d7ace3f
|
||||
timeCreated: 1452857267
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
9
Assets/MinValueAttribute.meta
Normal file
9
Assets/MinValueAttribute.meta
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9ad541daae932084a874bba45d821e60
|
||||
folderAsset: yes
|
||||
timeCreated: 1476957694
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
9
Assets/MinValueAttribute/Editor.meta
Normal file
9
Assets/MinValueAttribute/Editor.meta
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 32a49e8d55dc4c848ae0d5a0aca3b357
|
||||
folderAsset: yes
|
||||
timeCreated: 1447329667
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
23
Assets/MinValueAttribute/Editor/MinValueDrawer.cs
Normal file
23
Assets/MinValueAttribute/Editor/MinValueDrawer.cs
Normal file
@ -0,0 +1,23 @@
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
[CustomPropertyDrawer (typeof (MinValueAttribute))]
|
||||
public class MinValueDrawer : PropertyDrawer {
|
||||
|
||||
public override void OnGUI (Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
if (property.propertyType != SerializedPropertyType.Float && property.propertyType != SerializedPropertyType.Integer)
|
||||
{
|
||||
EditorGUI.LabelField (position, label.text, "Use MinValue with float or int.");
|
||||
return;
|
||||
}
|
||||
|
||||
EditorGUI.PropertyField(position, property, label);
|
||||
|
||||
if (GUI.changed)
|
||||
{
|
||||
MinValueAttribute minValue = attribute as MinValueAttribute;
|
||||
property.floatValue = Mathf.Max(property.floatValue, minValue.min);
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/MinValueAttribute/Editor/MinValueDrawer.cs.meta
Normal file
12
Assets/MinValueAttribute/Editor/MinValueDrawer.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: af909d555c4764145b02bd06b0c9646d
|
||||
timeCreated: 1447329696
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
11
Assets/MinValueAttribute/MinValueAttribute.cs
Normal file
11
Assets/MinValueAttribute/MinValueAttribute.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class MinValueAttribute : PropertyAttribute
|
||||
{
|
||||
public float min;
|
||||
|
||||
public MinValueAttribute (float min)
|
||||
{
|
||||
this.min = min;
|
||||
}
|
||||
}
|
12
Assets/MinValueAttribute/MinValueAttribute.cs.meta
Normal file
12
Assets/MinValueAttribute/MinValueAttribute.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b2932d2cdf3aaea4abe51315dc89f761
|
||||
timeCreated: 1447329589
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
9
Assets/Scenes.meta
Normal file
9
Assets/Scenes.meta
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 08cc8bb0acab7fa4f89387fd57ea92f5
|
||||
folderAsset: yes
|
||||
timeCreated: 1477661017
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
1601
Assets/Scenes/Area light.unity
Normal file
1601
Assets/Scenes/Area light.unity
Normal file
File diff suppressed because it is too large
Load Diff
8
Assets/Scenes/Area light.unity.meta
Normal file
8
Assets/Scenes/Area light.unity.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e4b4074801779784da23d0db51071030
|
||||
timeCreated: 1477663661
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
9
Assets/Scenes/Materials.meta
Normal file
9
Assets/Scenes/Materials.meta
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 44021e8904d04fa4bab45700dd060f65
|
||||
folderAsset: yes
|
||||
timeCreated: 1477748594
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
190
Assets/Scenes/Materials/blck.mat
Normal file
190
Assets/Scenes/Materials/blck.mat
Normal file
@ -0,0 +1,190 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 0}
|
||||
m_Name: blck
|
||||
m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_ShaderKeywords: _EMISSION
|
||||
m_LightmapFlags: 1
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap: {}
|
||||
m_SavedProperties:
|
||||
serializedVersion: 2
|
||||
m_TexEnvs:
|
||||
- first:
|
||||
name: _BumpMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- first:
|
||||
name: _DetailAlbedoMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- first:
|
||||
name: _DetailMask
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- first:
|
||||
name: _DetailNormalMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- first:
|
||||
name: _EmissionMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- first:
|
||||
name: _MainTex
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- first:
|
||||
name: _MetallicGlossMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- first:
|
||||
name: _OcclusionMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- first:
|
||||
name: _ParallaxMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- first:
|
||||
name: _SpecGlossMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Floats:
|
||||
- first:
|
||||
name: _BumpScale
|
||||
second: 1
|
||||
- first:
|
||||
name: _CullMode
|
||||
second: 2
|
||||
- first:
|
||||
name: _Cutoff
|
||||
second: 0.5
|
||||
- first:
|
||||
name: _DetailMode
|
||||
second: 0
|
||||
- first:
|
||||
name: _DetailNormalMapScale
|
||||
second: 1
|
||||
- first:
|
||||
name: _DstBlend
|
||||
second: 0
|
||||
- first:
|
||||
name: _GlossMapScale
|
||||
second: 1
|
||||
- first:
|
||||
name: _Glossiness
|
||||
second: 0.633
|
||||
- first:
|
||||
name: _GlossyReflections
|
||||
second: 1
|
||||
- first:
|
||||
name: _LightProbeScale
|
||||
second: 1
|
||||
- first:
|
||||
name: _MetaDiffuseScale
|
||||
second: 1
|
||||
- first:
|
||||
name: _MetaEmissionScale
|
||||
second: 1
|
||||
- first:
|
||||
name: _MetaMetallicSoup
|
||||
second: 1
|
||||
- first:
|
||||
name: _MetaSpecularScale
|
||||
second: 1
|
||||
- first:
|
||||
name: _MetaUseCustom
|
||||
second: 0
|
||||
- first:
|
||||
name: _Metallic
|
||||
second: 0
|
||||
- first:
|
||||
name: _Mode
|
||||
second: 0
|
||||
- first:
|
||||
name: _OcclusionStrength
|
||||
second: 1
|
||||
- first:
|
||||
name: _Parallax
|
||||
second: 0.02
|
||||
- first:
|
||||
name: _ReflectionProbeBoost
|
||||
second: 1
|
||||
- first:
|
||||
name: _SmoothnessTextureChannel
|
||||
second: 0
|
||||
- first:
|
||||
name: _SpecularHighlights
|
||||
second: 1
|
||||
- first:
|
||||
name: _SrcBlend
|
||||
second: 1
|
||||
- first:
|
||||
name: _Translucency
|
||||
second: 0
|
||||
- first:
|
||||
name: _UVDetailMask
|
||||
second: 0
|
||||
- first:
|
||||
name: _UVSec
|
||||
second: 0
|
||||
- first:
|
||||
name: _VertexOcclusionPower
|
||||
second: 1
|
||||
- first:
|
||||
name: _ZWrite
|
||||
second: 1
|
||||
m_Colors:
|
||||
- first:
|
||||
name: _Color
|
||||
second: {r: 0.16176468, g: 0.16176468, b: 0.16176468, a: 1}
|
||||
- first:
|
||||
name: _EmissionColor
|
||||
second: {r: 0, g: 0, b: 0, a: 1}
|
||||
- first:
|
||||
name: _MetaDiffuseAdd
|
||||
second: {r: 0, g: 0, b: 0, a: 1}
|
||||
- first:
|
||||
name: _MetaDiffuseTint
|
||||
second: {r: 1, g: 1, b: 1, a: 1}
|
||||
- first:
|
||||
name: _MetaEmissionAdd
|
||||
second: {r: 0, g: 0, b: 0, a: 1}
|
||||
- first:
|
||||
name: _MetaEmissionTint
|
||||
second: {r: 1, g: 1, b: 1, a: 1}
|
||||
- first:
|
||||
name: _MetaSpecularAdd
|
||||
second: {r: 0, g: 0, b: 0, a: 1}
|
||||
- first:
|
||||
name: _MetaSpecularTint
|
||||
second: {r: 1, g: 1, b: 1, a: 1}
|
||||
- first:
|
||||
name: _SpecColor
|
||||
second: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
|
8
Assets/Scenes/Materials/blck.mat.meta
Normal file
8
Assets/Scenes/Materials/blck.mat.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 407b0765066496e4da88d97aa9205037
|
||||
timeCreated: 1432511050
|
||||
licenseType: Pro
|
||||
NativeFormatImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
1859
Assets/Scenes/Tube lights and local fog density.unity
Normal file
1859
Assets/Scenes/Tube lights and local fog density.unity
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 54a18da41a501694a8e1980a2a897da7
|
||||
timeCreated: 1477692305
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 272d3d2fab1f6784dae6c85bdf479508
|
||||
timeCreated: 1477693506
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
9
Assets/TubeLight.meta
Normal file
9
Assets/TubeLight.meta
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7af1fbf5b0c3fc34e929a665f1822f98
|
||||
folderAsset: yes
|
||||
timeCreated: 1476957694
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
9
Assets/TubeLight/Editor.meta
Normal file
9
Assets/TubeLight/Editor.meta
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 95f79d7423b1c4239ba221be74ca9134
|
||||
folderAsset: yes
|
||||
timeCreated: 1446582841
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
62
Assets/TubeLight/Editor/TubeLightEditor.cs
Normal file
62
Assets/TubeLight/Editor/TubeLightEditor.cs
Normal file
@ -0,0 +1,62 @@
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using UnityEditor.AnimatedValues;
|
||||
|
||||
[CustomEditor(typeof(TubeLight))]
|
||||
[CanEditMultipleObjects]
|
||||
public class TubeLightEditor : Editor {
|
||||
|
||||
AnimFloat m_ShowInfo;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
m_ShowInfo = new AnimFloat(0);
|
||||
m_ShowInfo.valueChanged.AddListener(Repaint);
|
||||
m_ShowInfo.speed = 0.5f;
|
||||
}
|
||||
|
||||
override public void OnInspectorGUI()
|
||||
{
|
||||
DrawDefaultInspector();
|
||||
|
||||
if (targets.Length > 1)
|
||||
return;
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
if(GUILayout.Button("Add a shadow plane"))
|
||||
m_ShowInfo.value = AddShadowPlane() ? 0 : 100;
|
||||
|
||||
foreach (TubeLightShadowPlane shadowPlane in ((TubeLight)target).m_ShadowPlanes)
|
||||
if (shadowPlane != null)
|
||||
EditorGUILayout.ObjectField("Shadow Plane", shadowPlane, typeof(TubeLightShadowPlane), !EditorUtility.IsPersistent(target));
|
||||
|
||||
m_ShowInfo.target = 0;
|
||||
if (EditorGUILayout.BeginFadeGroup(Mathf.Min(1.0f, m_ShowInfo.value)))
|
||||
EditorGUILayout.HelpBox("Limit of " + TubeLight.maxPlanes + " planes reached. Delete an existing one.", MessageType.Info);
|
||||
EditorGUILayout.EndFadeGroup();
|
||||
}
|
||||
|
||||
bool AddShadowPlane()
|
||||
{
|
||||
TubeLight tubeLight = (TubeLight)target;
|
||||
|
||||
int i = 0;
|
||||
for (; i < TubeLight.maxPlanes; i++)
|
||||
{
|
||||
if (tubeLight.m_ShadowPlanes[i] != null)
|
||||
continue;
|
||||
|
||||
GameObject go = new GameObject("Shadow Plane");
|
||||
TubeLightShadowPlane shadowPlane = go.AddComponent<TubeLightShadowPlane>();
|
||||
|
||||
go.transform.position = tubeLight.transform.position + go.transform.forward;
|
||||
go.transform.parent = tubeLight.transform;
|
||||
tubeLight.m_ShadowPlanes[i] = shadowPlane;
|
||||
EditorUtility.SetDirty (tubeLight);
|
||||
break;
|
||||
}
|
||||
|
||||
return i < TubeLight.maxPlanes;
|
||||
}
|
||||
}
|
12
Assets/TubeLight/Editor/TubeLightEditor.cs.meta
Normal file
12
Assets/TubeLight/Editor/TubeLightEditor.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 00a6ee99a4a9a44879507a5c4077d7a0
|
||||
timeCreated: 1446582855
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
9
Assets/TubeLight/Scripts.meta
Normal file
9
Assets/TubeLight/Scripts.meta
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fa6f2ae72d2fc9643afe34db34a35a28
|
||||
folderAsset: yes
|
||||
timeCreated: 1477748611
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
327
Assets/TubeLight/Scripts/TubeLight.cs
Normal file
327
Assets/TubeLight/Scripts/TubeLight.cs
Normal file
@ -0,0 +1,327 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using System.Collections.Generic;
|
||||
|
||||
[ExecuteInEditMode]
|
||||
public class TubeLight : MonoBehaviour
|
||||
{
|
||||
public float m_Intensity = 0.8f;
|
||||
public Color m_Color = Color.white;
|
||||
public float m_Range = 10.0f;
|
||||
public float m_Radius = 0.3f;
|
||||
public float m_Length = 0.0f;
|
||||
|
||||
[HideInInspector]
|
||||
public Mesh m_Sphere;
|
||||
[HideInInspector]
|
||||
public Mesh m_Capsule;
|
||||
[HideInInspector]
|
||||
public Shader m_ProxyShader;
|
||||
Material m_ProxyMaterial;
|
||||
|
||||
public bool m_RenderSource = false;
|
||||
Renderer m_SourceRenderer;
|
||||
Transform m_SourceTransform;
|
||||
Mesh m_SourceMesh;
|
||||
float m_LastLength = -1;
|
||||
|
||||
public const int maxPlanes = 2;
|
||||
[HideInInspector]
|
||||
public TubeLightShadowPlane[] m_ShadowPlanes = new TubeLightShadowPlane[maxPlanes];
|
||||
|
||||
bool m_Initialized = false;
|
||||
MaterialPropertyBlock m_props;
|
||||
|
||||
const float kMinRadius = 0.001f;
|
||||
bool renderSource {get{return m_RenderSource && m_Radius >= kMinRadius;}}
|
||||
|
||||
Dictionary<Camera, CommandBuffer> m_Cameras = new Dictionary<Camera, CommandBuffer>();
|
||||
static CameraEvent kCameraEvent = CameraEvent.AfterLighting;
|
||||
|
||||
void Start()
|
||||
{
|
||||
if(!Init())
|
||||
return;
|
||||
UpdateMeshesAndBounds();
|
||||
}
|
||||
|
||||
bool Init()
|
||||
{
|
||||
if (m_Initialized)
|
||||
return true;
|
||||
|
||||
// Sometimes on editor startup (especially after project upgrade?), Init() gets called
|
||||
// while m_ProxyShader, m_Sphere or m_Capsule is still null/hasn't loaded.
|
||||
if (m_ProxyShader == null || m_Sphere == null || m_Capsule == null)
|
||||
return false;
|
||||
|
||||
// Proxy
|
||||
m_ProxyMaterial = new Material(m_ProxyShader);
|
||||
m_ProxyMaterial.hideFlags = HideFlags.HideAndDontSave;
|
||||
|
||||
// Source
|
||||
m_SourceMesh = Instantiate<Mesh>(m_Capsule);
|
||||
m_SourceMesh.hideFlags = HideFlags.HideAndDontSave;
|
||||
|
||||
// Can't create the MeshFilter here, since for some reason the DontSave flag has
|
||||
// no effect on it. Has to be added to the prefab instead.
|
||||
//m_SourceMeshFilter = gameObject.AddComponent<MeshFilter>();
|
||||
MeshFilter mfs = gameObject.GetComponent<MeshFilter>();
|
||||
// Hmm, causes trouble
|
||||
// mfs.hideFlags = HideFlags.HideInInspector;
|
||||
mfs.sharedMesh = m_SourceMesh;
|
||||
|
||||
// A similar problem here.
|
||||
// m_SourceRenderer = gameObject.AddComponent<MeshRenderer>();
|
||||
m_SourceRenderer = gameObject.GetComponent<MeshRenderer>();
|
||||
m_SourceRenderer.enabled = true;
|
||||
|
||||
// We want it to be pickable in the scene view, so no HideAndDontSave
|
||||
// Hmm, causes trouble
|
||||
// m_SourceRenderer.hideFlags = HideFlags.DontSave | HideFlags.HideInInspector;
|
||||
|
||||
m_SourceTransform = transform;
|
||||
|
||||
m_Initialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
if(m_props == null)
|
||||
m_props = new MaterialPropertyBlock();
|
||||
|
||||
if(!Init())
|
||||
return;
|
||||
UpdateMeshesAndBounds();
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
if(!Application.isPlaying)
|
||||
Cleanup();
|
||||
else
|
||||
for(var e = m_Cameras.GetEnumerator(); e.MoveNext();)
|
||||
if(e.Current.Value != null)
|
||||
e.Current.Value.Clear();
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
if (m_ProxyMaterial != null)
|
||||
DestroyImmediate(m_ProxyMaterial);
|
||||
if (m_SourceMesh != null)
|
||||
DestroyImmediate(m_SourceMesh);
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
void Cleanup()
|
||||
{
|
||||
for(var e = m_Cameras.GetEnumerator(); e.MoveNext();)
|
||||
{
|
||||
var cam = e.Current;
|
||||
if(cam.Key != null && cam.Value != null)
|
||||
cam.Key.RemoveCommandBuffer (kCameraEvent, cam.Value);
|
||||
}
|
||||
m_Cameras.Clear();
|
||||
}
|
||||
|
||||
void UpdateMeshesAndBounds()
|
||||
{
|
||||
// Sanitize
|
||||
m_Range = Mathf.Max(m_Range, 0);
|
||||
m_Radius = Mathf.Max(m_Radius, 0);
|
||||
m_Length = Mathf.Max(m_Length, 0);
|
||||
m_Intensity = Mathf.Max(m_Intensity, 0);
|
||||
|
||||
Vector3 sourceSize = renderSource ? Vector3.one * m_Radius * 2.0f : Vector3.one;
|
||||
if (m_SourceTransform.localScale != sourceSize || m_Length != m_LastLength)
|
||||
{
|
||||
m_LastLength = m_Length;
|
||||
|
||||
Vector3[] vertices = m_Capsule.vertices;
|
||||
for (int i = 0; i < vertices.Length; i++)
|
||||
{
|
||||
if (renderSource)
|
||||
vertices[i].y += Mathf.Sign(vertices[i].y) * (- 0.5f + 0.25f * m_Length / m_Radius);
|
||||
else
|
||||
vertices[i] = Vector3.one * 0.0001f;
|
||||
}
|
||||
|
||||
m_SourceMesh.vertices = vertices;
|
||||
}
|
||||
|
||||
m_SourceTransform.localScale = sourceSize;
|
||||
|
||||
float range = m_Range + m_Radius;
|
||||
|
||||
// TODO: lazy for now, should draw a tight capsule
|
||||
range += 0.5f * m_Length;
|
||||
range *= 1.02f;
|
||||
|
||||
range /= m_Radius;
|
||||
|
||||
m_SourceMesh.bounds = new Bounds(Vector3.zero, Vector3.one * range);
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if(!Init())
|
||||
return;
|
||||
|
||||
UpdateMeshesAndBounds();
|
||||
|
||||
if(Application.isPlaying)
|
||||
for(var e = m_Cameras.GetEnumerator(); e.MoveNext();)
|
||||
if(e.Current.Value != null)
|
||||
e.Current.Value.Clear();
|
||||
}
|
||||
|
||||
Color GetColor()
|
||||
{
|
||||
if (QualitySettings.activeColorSpace == ColorSpace.Gamma)
|
||||
return m_Color * m_Intensity;
|
||||
|
||||
return new Color(
|
||||
Mathf.GammaToLinearSpace(m_Color.r * m_Intensity),
|
||||
Mathf.GammaToLinearSpace(m_Color.g * m_Intensity),
|
||||
Mathf.GammaToLinearSpace(m_Color.b * m_Intensity),
|
||||
1.0f
|
||||
);
|
||||
}
|
||||
|
||||
void OnWillRenderObject()
|
||||
{
|
||||
if(InsideShadowmapCameraRender())
|
||||
return;
|
||||
|
||||
if(!Init())
|
||||
return;
|
||||
|
||||
// TODO: This is just a very rough guess. Need to properly calculate the surface emission
|
||||
// intensity based on light's intensity.
|
||||
m_props.SetVector("_EmissionColor", m_Color * Mathf.Sqrt(m_Intensity) * 2.0f);
|
||||
m_SourceRenderer.SetPropertyBlock(m_props);
|
||||
|
||||
SetUpCommandBuffer();
|
||||
}
|
||||
|
||||
void SetUpCommandBuffer()
|
||||
{
|
||||
Camera cam = Camera.current;
|
||||
CommandBuffer buf = null;
|
||||
if (!m_Cameras.ContainsKey(cam))
|
||||
{
|
||||
buf = new CommandBuffer();
|
||||
buf.name = gameObject.name;
|
||||
m_Cameras[cam] = buf;
|
||||
cam.AddCommandBuffer(kCameraEvent, buf);
|
||||
cam.depthTextureMode |= DepthTextureMode.Depth;
|
||||
}
|
||||
else
|
||||
{
|
||||
buf = m_Cameras[cam];
|
||||
buf.Clear();
|
||||
}
|
||||
|
||||
Transform t = transform;
|
||||
Vector3 lightAxis = t.up;
|
||||
Vector3 lightPos = t.position - 0.5f * lightAxis * m_Length;
|
||||
buf.SetGlobalVector("_LightPos", new Vector4(lightPos.x, lightPos.y, lightPos.z, 1.0f/(m_Range*m_Range)));
|
||||
buf.SetGlobalVector("_LightAxis", new Vector4(lightAxis.x, lightAxis.y, lightAxis.z, 0.0f));
|
||||
buf.SetGlobalFloat("_LightAsQuad", 0);
|
||||
buf.SetGlobalFloat("_LightRadius", m_Radius);
|
||||
buf.SetGlobalFloat("_LightLength", m_Length);
|
||||
buf.SetGlobalVector("_LightColor", GetColor());
|
||||
|
||||
SetShadowPlaneVectors(buf);
|
||||
|
||||
float range = m_Range + m_Radius;
|
||||
// TODO: lazy for now, should draw a tight capsule
|
||||
range += 0.5f * m_Length;
|
||||
range *= 1.02f;
|
||||
range /= m_Radius;
|
||||
|
||||
Matrix4x4 m = Matrix4x4.Scale(Vector3.one * range);
|
||||
buf.DrawMesh(m_Sphere, t.localToWorldMatrix * m, m_ProxyMaterial, 0, 0);
|
||||
}
|
||||
|
||||
public TubeLightShadowPlane.Params[] GetShadowPlaneParams(ref TubeLightShadowPlane.Params[] p)
|
||||
{
|
||||
if (p == null || p.Length != maxPlanes)
|
||||
p = new TubeLightShadowPlane.Params[maxPlanes];
|
||||
for(int i = 0; i < maxPlanes; i++)
|
||||
{
|
||||
TubeLightShadowPlane sp = m_ShadowPlanes[i];
|
||||
p[i].plane = sp == null ? new Vector4(0, 0, 0, 1) : sp.GetShadowPlaneVector();
|
||||
p[i].feather = sp == null ? 1 : sp.feather;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
TubeLightShadowPlane.Params[] sppArr = new TubeLightShadowPlane.Params[maxPlanes];
|
||||
|
||||
void SetShadowPlaneVectors(CommandBuffer buf)
|
||||
{
|
||||
var p = GetShadowPlaneParams(ref sppArr);
|
||||
|
||||
for (int i = 0, n = p.Length; i < n; ++i)
|
||||
{
|
||||
var spp = p[i];
|
||||
if(i == 0) {
|
||||
buf.SetGlobalVector("_ShadowPlane0", spp.plane);
|
||||
buf.SetGlobalFloat("_ShadowPlaneFeather0", spp.feather);
|
||||
} else if(i == 1) {
|
||||
buf.SetGlobalVector("_ShadowPlane1", spp.plane);
|
||||
buf.SetGlobalFloat("_ShadowPlaneFeather1", spp.feather);
|
||||
} else {
|
||||
buf.SetGlobalVector("_ShadowPlane" + i, spp.plane);
|
||||
buf.SetGlobalFloat("_ShadowPlaneFeather" + i, spp.feather);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnDrawGizmosSelected()
|
||||
{
|
||||
if (m_SourceTransform == null)
|
||||
return;
|
||||
|
||||
Gizmos.color = Color.white;
|
||||
// Skip the scale
|
||||
Matrix4x4 m = new Matrix4x4();
|
||||
m.SetTRS(m_SourceTransform.position, m_SourceTransform.rotation, Vector3.one);
|
||||
Gizmos.matrix = m;
|
||||
|
||||
Gizmos.DrawWireSphere(Vector3.zero, m_Radius + m_Range + 0.5f * m_Length);
|
||||
|
||||
Vector3 start = 0.5f * Vector3.up * m_Length;
|
||||
Gizmos.DrawWireSphere(start, m_Radius);
|
||||
|
||||
if (m_Length == 0.0f)
|
||||
return;
|
||||
|
||||
Vector3 end = - 0.5f * Vector3.up * m_Length;
|
||||
Gizmos.DrawWireSphere(end, m_Radius);
|
||||
|
||||
Vector3 r = Vector3.forward * m_Radius;
|
||||
Gizmos.DrawLine(start + r, end + r);
|
||||
Gizmos.DrawLine(start - r, end - r);
|
||||
|
||||
r = Vector3.right * m_Radius;
|
||||
Gizmos.DrawLine(start + r, end + r);
|
||||
Gizmos.DrawLine(start - r, end - r);
|
||||
|
||||
}
|
||||
|
||||
void OnDrawGizmos()
|
||||
{
|
||||
// TODO: Looks like this changed the name. Find a more robust way to use the icon.
|
||||
// Gizmos.DrawIcon(transform.position, "PointLight Gizmo_MIP0.png", true);
|
||||
}
|
||||
|
||||
bool InsideShadowmapCameraRender()
|
||||
{
|
||||
RenderTexture target = Camera.current.targetTexture;
|
||||
return target != null && target.format == RenderTextureFormat.Shadowmap;
|
||||
}
|
||||
}
|
16
Assets/TubeLight/Scripts/TubeLight.cs.meta
Normal file
16
Assets/TubeLight/Scripts/TubeLight.cs.meta
Normal file
@ -0,0 +1,16 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5a3b99ed98424ea4587ec18d930a1d77
|
||||
timeCreated: 1444638222
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences:
|
||||
- m_Sphere: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0}
|
||||
- m_Capsule: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0}
|
||||
- m_ProxyShader: {fileID: 4800000, guid: 2e6fd90941a3e3c458d01f851dca21ed, type: 3}
|
||||
- m_SourceShader: {fileID: 10755, guid: 0000000000000000f000000000000000, type: 0}
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
32
Assets/TubeLight/Scripts/TubeLightShadowPlane.cs
Normal file
32
Assets/TubeLight/Scripts/TubeLightShadowPlane.cs
Normal file
@ -0,0 +1,32 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class TubeLightShadowPlane : MonoBehaviour
|
||||
{
|
||||
[MinValue(0)]
|
||||
public float m_Feather = 1.0f;
|
||||
|
||||
public float feather {get{ return m_Feather * 0.1f;}}
|
||||
|
||||
public Vector4 GetShadowPlaneVector()
|
||||
{
|
||||
Transform t = transform;
|
||||
Vector3 v = t.forward;
|
||||
float d = Vector3.Dot(t.position, v);
|
||||
return new Vector4(v.x, v.y, v.z, d);
|
||||
}
|
||||
|
||||
void OnDrawGizmosSelected()
|
||||
{
|
||||
Matrix4x4 m = Matrix4x4.zero;
|
||||
Transform t = transform;
|
||||
m.SetTRS(t.position, t.rotation, new Vector3(1, 1, 0));
|
||||
Gizmos.matrix = m;
|
||||
Gizmos.DrawWireSphere(Vector3.zero, 1);
|
||||
}
|
||||
|
||||
public struct Params
|
||||
{
|
||||
public Vector4 plane;
|
||||
public float feather;
|
||||
}
|
||||
}
|
12
Assets/TubeLight/Scripts/TubeLightShadowPlane.cs.meta
Normal file
12
Assets/TubeLight/Scripts/TubeLightShadowPlane.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 66d8e50a047abb54aa901236f0ed84d2
|
||||
timeCreated: 1446129202
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
9
Assets/TubeLight/Shaders.meta
Normal file
9
Assets/TubeLight/Shaders.meta
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b041de53e70b28e4fb9256c930c13615
|
||||
folderAsset: yes
|
||||
timeCreated: 1477749221
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
189
Assets/TubeLight/Shaders/TubeLight.cginc
Normal file
189
Assets/TubeLight/Shaders/TubeLight.cginc
Normal file
@ -0,0 +1,189 @@
|
||||
// Based on 'Real Shading in Unreal Engine 4'
|
||||
// http://blog.selfshadow.com/publications/s2013-shading-course/#course_content
|
||||
|
||||
#include "TubeLightAttenuation.cginc"
|
||||
|
||||
#ifndef SHADOW_PLANES
|
||||
#define SHADOW_PLANES 1
|
||||
#endif
|
||||
|
||||
#if SHADOW_PLANES
|
||||
#include "TubeLightShadowPlanes.cginc"
|
||||
#endif
|
||||
|
||||
#define SHARP_EDGE_FIX 1
|
||||
|
||||
void SphereLightToPointLight(float3 pos, float3 lightPos, float3 eyeVec, half3 normal, float sphereRad, half rangeSqInv, inout UnityLight light, out half lightDist)
|
||||
{
|
||||
half3 viewDir = -eyeVec;
|
||||
half3 r = reflect (viewDir, normal);
|
||||
|
||||
float3 L = lightPos - pos;
|
||||
float3 centerToRay = dot (L, r) * r - L;
|
||||
float3 closestPoint = L + centerToRay * saturate(sphereRad / length(centerToRay));
|
||||
|
||||
lightDist = length(closestPoint);
|
||||
light.dir = closestPoint / lightDist;
|
||||
|
||||
half distLSq = dot(L, L);
|
||||
light.ndotl = saturate(dot(normal, L/sqrt(distLSq)));
|
||||
|
||||
float distNorm = distLSq * rangeSqInv;
|
||||
float atten = AttenuationToZero(distNorm);
|
||||
light.color *= atten;
|
||||
}
|
||||
|
||||
void TubeLightToPointLight(float3 pos, float3 tubeStart, float3 tubeEnd, float3 normal, float tubeRad, float rangeSqInv, float3 representativeDir, float3 lightColor, out float3 outLightColor, out float3 outLightDir, out float outNdotL, out half outLightDist)
|
||||
{
|
||||
half3 N = normal;
|
||||
float3 L0 = tubeStart - pos;
|
||||
float3 L1 = tubeEnd - pos;
|
||||
float L0dotL0 = dot(L0, L0);
|
||||
float distL0 = sqrt(L0dotL0);
|
||||
float distL1 = length(L1);
|
||||
|
||||
float NdotL0 = dot(L0, N) / (2.0 * distL0);
|
||||
float NdotL1 = dot(L1, N) / (2.0 * distL1);
|
||||
outNdotL = saturate(NdotL0 + NdotL1);
|
||||
|
||||
float3 Ldir = L1 - L0;
|
||||
float RepdotL0 = dot(representativeDir, L0);
|
||||
float RepdotLdir = dot(representativeDir, Ldir);
|
||||
float L0dotLdir = dot(L0, Ldir);
|
||||
float LdirdotLdir = dot(Ldir, Ldir);
|
||||
float distLdir = sqrt(LdirdotLdir);
|
||||
|
||||
#if SHARP_EDGE_FIX
|
||||
// There's a very visible discontinuity if we just take the closest distance to ray,
|
||||
// as the original paper suggests. This is an attempt to fix it, but it gets slightly more expensive and
|
||||
// has its own artifact, although this time at least C0 smooth.
|
||||
|
||||
// Smallest angle to ray
|
||||
float t = (L0dotLdir * RepdotL0 - L0dotL0 * RepdotLdir) / (L0dotLdir * RepdotLdir - LdirdotLdir * RepdotL0);
|
||||
t = saturate(t);
|
||||
|
||||
// As representativeDir becomes parallel (well, in some plane) to Ldir and then points away, t flips from 0 to 1 (or vv) and a discontinuity shows up.
|
||||
// Counteract by detecting that relative angle/position and flip t. The discontinuity in t moves to the back side.
|
||||
float3 L0xLdir = cross(L0, Ldir);
|
||||
float3 LdirxR = cross(Ldir, representativeDir);
|
||||
float RepAtLdir = dot(L0xLdir, LdirxR);
|
||||
|
||||
// RepAtLdir is negative if R points away from Ldir.
|
||||
// TODO: check if lerp below is indeed cheaper.
|
||||
// if (RepAtLdir < 0)
|
||||
// t = 1 - t;
|
||||
t = lerp(1 - t, t, step(0, RepAtLdir));
|
||||
|
||||
#else
|
||||
// Original by Karis
|
||||
// Closest distance to ray
|
||||
float t = (RepdotL0 * RepdotLdir - L0dotLdir) / (distLdir * distLdir - RepdotLdir * RepdotLdir);
|
||||
t = saturate(t);
|
||||
|
||||
#endif
|
||||
|
||||
float3 closestPoint = L0 + Ldir * t;
|
||||
float3 centerToRay = dot(closestPoint, representativeDir) * representativeDir - closestPoint;
|
||||
|
||||
closestPoint = closestPoint + centerToRay * saturate(tubeRad / length(centerToRay));
|
||||
|
||||
outLightDist = length(closestPoint);
|
||||
outLightDir = closestPoint / outLightDist;
|
||||
|
||||
float distNorm = 0.5f * (distL0 * distL1 + dot(L0, L1)) * rangeSqInv;
|
||||
outLightColor = lightColor * AttenuationToZero(distNorm);
|
||||
}
|
||||
|
||||
void TubeLightToPointLight(float3 pos, float3 tubeStart, float3 tubeEnd, float3 eyeVec, float3 normal, float tubeRad, float rangeSqInv, float3 lightColor, out float3 outLightColor, out float3 outLightDir, out float outNdotL, out half outLightDist)
|
||||
{
|
||||
half3 viewDir = -eyeVec;
|
||||
half3 representativeDir = reflect (viewDir, normal);
|
||||
|
||||
TubeLightToPointLight(pos, tubeStart, tubeEnd, normal, tubeRad, rangeSqInv, representativeDir, lightColor, outLightColor, outLightDir, outNdotL, outLightDist);
|
||||
}
|
||||
|
||||
inline half GGXTerm_Area (half NdotH, half roughness, half lightDist, half lightRadius)
|
||||
{
|
||||
half a = roughness * roughness;
|
||||
half a2 = a * a;
|
||||
half d = NdotH * NdotH * (a2 - 1.f) + 1.f;
|
||||
d = max(d, 0.000001);
|
||||
|
||||
half aP = saturate( lightRadius / (lightDist*2.0) + a);
|
||||
half aP2 = aP * aP;
|
||||
|
||||
return a2 * a2 / (UNITY_PI * d * d * aP2);
|
||||
}
|
||||
|
||||
half4 BRDF1_Unity_PBS_Area (half3 diffColor, half3 specColor, half oneMinusReflectivity, half oneMinusRoughness,
|
||||
half3 normal, half3 viewDir,
|
||||
UnityLight light, UnityIndirect gi, half lightDist, half lightRadius)
|
||||
{
|
||||
half roughness = 1-oneMinusRoughness;
|
||||
half3 halfDir = Unity_SafeNormalize (light.dir + viewDir);
|
||||
|
||||
half nl = light.ndotl;
|
||||
half nh = BlinnTerm (normal, halfDir);
|
||||
half nv = DotClamped (normal, viewDir);
|
||||
half lv = DotClamped (light.dir, viewDir);
|
||||
half lh = DotClamped (light.dir, halfDir);
|
||||
|
||||
half V = SmithGGXVisibilityTerm (nl, nv, roughness);
|
||||
half D = GGXTerm_Area (nh, roughness, lightDist, lightRadius);
|
||||
|
||||
half nlPow5 = Pow5 (1-nl);
|
||||
half nvPow5 = Pow5 (1-nv);
|
||||
half Fd90 = 0.5 + 2 * lh * lh * roughness;
|
||||
half disneyDiffuse = (1 + (Fd90-1) * nlPow5) * (1 + (Fd90-1) * nvPow5);
|
||||
|
||||
// HACK: theoretically we should divide by Pi diffuseTerm and not multiply specularTerm!
|
||||
// BUT 1) that will make shader look significantly darker than Legacy ones
|
||||
// and 2) on engine side "Non-important" lights have to be divided by Pi to in cases when they are injected into ambient SH
|
||||
// NOTE: multiplication by Pi is part of single constant together with 1/4 now
|
||||
|
||||
half specularTerm = (V * D) * (UNITY_PI/4); // Torrance-Sparrow model, Fresnel is applied later (for optimization reasons)
|
||||
if (IsGammaSpace())
|
||||
specularTerm = sqrt(max(1e-4h, specularTerm));
|
||||
specularTerm = max(0, specularTerm * nl);
|
||||
half diffuseTerm = disneyDiffuse * nl;
|
||||
|
||||
half grazingTerm = saturate(oneMinusRoughness + (1-oneMinusReflectivity));
|
||||
half3 color = diffColor * (gi.diffuse + light.color * diffuseTerm)
|
||||
+ specularTerm * light.color * FresnelTerm (specColor, lh)
|
||||
+ gi.specular * FresnelLerp (specColor, grazingTerm, nv);
|
||||
|
||||
return half4(color, 1);
|
||||
}
|
||||
|
||||
half4 CalculateLight (float3 worldPos, float2 uv, half3 baseColor, half3 specColor, half oneMinusRoughness, half3 normalWorld,
|
||||
half3 lightStart, half3 lightEnd, half3 lightColor, half lightRadius, half lightRangeSqInv)
|
||||
{
|
||||
UnityLight light = (UnityLight)0;
|
||||
|
||||
float3 eyeVec = normalize(worldPos - _WorldSpaceCameraPos);
|
||||
half lightDist = 0;
|
||||
|
||||
#if 0
|
||||
// Can't use a keyword, because no keywords in material property blocks.
|
||||
// TODO: is it worth the dynamic branch?
|
||||
if (sphereLight)
|
||||
SphereLightToPointLight (worldPos, lightStart, eyeVec, normalWorld, lightRadius, lightRangeSqInv, light, lightDist);
|
||||
else
|
||||
#else
|
||||
TubeLightToPointLight (worldPos, lightStart, lightEnd, eyeVec, normalWorld, lightRadius, lightRangeSqInv, lightColor, light.color, light.dir, light.ndotl, lightDist);
|
||||
#endif
|
||||
|
||||
#if SHADOW_PLANES
|
||||
light.color *= ShadowPlanes(worldPos);
|
||||
#endif
|
||||
|
||||
half oneMinusReflectivity = 1 - SpecularStrength(specColor.rgb);
|
||||
|
||||
UnityIndirect ind;
|
||||
UNITY_INITIALIZE_OUTPUT(UnityIndirect, ind);
|
||||
ind.diffuse = 0;
|
||||
ind.specular = 0;
|
||||
|
||||
half4 res = BRDF1_Unity_PBS_Area (baseColor, specColor, oneMinusReflectivity, oneMinusRoughness, normalWorld, -eyeVec, light, ind, lightDist, lightRadius);
|
||||
return res;
|
||||
}
|
9
Assets/TubeLight/Shaders/TubeLight.cginc.meta
Normal file
9
Assets/TubeLight/Shaders/TubeLight.cginc.meta
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bea54fea6aabea841b90651d989d88f5
|
||||
timeCreated: 1452380090
|
||||
licenseType: Pro
|
||||
ShaderImporter:
|
||||
defaultTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
87
Assets/TubeLight/Shaders/TubeLight.shader
Normal file
87
Assets/TubeLight/Shaders/TubeLight.shader
Normal file
@ -0,0 +1,87 @@
|
||||
Shader "Hidden/TubeLight" {
|
||||
SubShader {
|
||||
Tags { "Queue"="Geometry-1" }
|
||||
|
||||
CGINCLUDE
|
||||
#include "UnityCG.cginc"
|
||||
#include "UnityPBSLighting.cginc"
|
||||
#include "UnityDeferredLibrary.cginc"
|
||||
|
||||
#define SHADOW_PLANES 1
|
||||
#include "TubeLight.cginc"
|
||||
|
||||
sampler2D _CameraGBufferTexture0;
|
||||
sampler2D _CameraGBufferTexture1;
|
||||
sampler2D _CameraGBufferTexture2;
|
||||
|
||||
float _LightRadius;
|
||||
float _LightLength;
|
||||
float4 _LightAxis;
|
||||
|
||||
|
||||
void DeferredCalculateLightParams (
|
||||
unity_v2f_deferred i,
|
||||
out float3 outWorldPos,
|
||||
out float2 outUV)
|
||||
{
|
||||
i.ray = i.ray * (_ProjectionParams.z / i.ray.z);
|
||||
float2 uv = i.uv.xy / i.uv.w;
|
||||
|
||||
// read depth and reconstruct world position
|
||||
float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv);
|
||||
depth = Linear01Depth (depth);
|
||||
float4 vpos = float4(i.ray * depth,1);
|
||||
float3 wpos = mul (unity_CameraToWorld, vpos).xyz;
|
||||
|
||||
outWorldPos = wpos;
|
||||
outUV = uv;
|
||||
}
|
||||
|
||||
half4 CalculateLightDeferred (unity_v2f_deferred i)
|
||||
{
|
||||
float3 worldPos;
|
||||
float2 uv;
|
||||
DeferredCalculateLightParams (i, worldPos, uv);
|
||||
|
||||
half4 gbuffer0 = tex2D (_CameraGBufferTexture0, uv);
|
||||
half4 gbuffer1 = tex2D (_CameraGBufferTexture1, uv);
|
||||
half4 gbuffer2 = tex2D (_CameraGBufferTexture2, uv);
|
||||
|
||||
half3 baseColor = gbuffer0.rgb;
|
||||
half3 specColor = gbuffer1.rgb;
|
||||
half oneMinusRoughness = gbuffer1.a;
|
||||
half3 normalWorld = gbuffer2.rgb * 2 - 1;
|
||||
normalWorld = normalize(normalWorld);
|
||||
|
||||
return CalculateLight (worldPos, uv, baseColor, specColor, oneMinusRoughness, normalWorld,
|
||||
_LightPos.xyz, _LightPos.xyz + _LightAxis.xyz * _LightLength, _LightColor.xyz, _LightRadius, _LightPos.w);
|
||||
}
|
||||
ENDCG
|
||||
|
||||
Pass {
|
||||
Fog { Mode Off }
|
||||
ZWrite Off
|
||||
Blend One One
|
||||
Cull Front
|
||||
ZTest Always
|
||||
|
||||
|
||||
CGPROGRAM
|
||||
#pragma target 3.0
|
||||
#pragma vertex vert_deferred
|
||||
#pragma fragment frag
|
||||
#pragma exclude_renderers nomrt
|
||||
|
||||
fixed4 frag (unity_v2f_deferred i) : SV_Target
|
||||
{
|
||||
half4 light = CalculateLightDeferred(i);
|
||||
// TODO: squash those NaNs at their source
|
||||
return isnan(light) ? 0 : light;
|
||||
}
|
||||
|
||||
ENDCG
|
||||
}
|
||||
|
||||
}
|
||||
Fallback Off
|
||||
}
|
9
Assets/TubeLight/Shaders/TubeLight.shader.meta
Normal file
9
Assets/TubeLight/Shaders/TubeLight.shader.meta
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2e6fd90941a3e3c458d01f851dca21ed
|
||||
timeCreated: 1442344786
|
||||
licenseType: Pro
|
||||
ShaderImporter:
|
||||
defaultTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
55
Assets/TubeLight/Shaders/TubeLightAttenuation.cginc
Normal file
55
Assets/TubeLight/Shaders/TubeLightAttenuation.cginc
Normal file
@ -0,0 +1,55 @@
|
||||
#ifndef TUBE_LIGHT_ATTENUATION_LEGACY
|
||||
#define TUBE_LIGHT_ATTENUATION_LEGACY 0
|
||||
#endif
|
||||
|
||||
#if TUBE_LIGHT_ATTENUATION_LEGACY
|
||||
|
||||
float Attenuation(float distNorm)
|
||||
{
|
||||
return 1.0 / (1.0 + 25.0 * distNorm);
|
||||
}
|
||||
|
||||
float AttenuationToZero(float distNorm)
|
||||
{
|
||||
float att = Attenuation(distNorm);
|
||||
|
||||
// Replicating unity light attenuation - pulled to 0 at range
|
||||
// if (distNorm > 0.8 * 0.8)
|
||||
// att *= 1 - (distNorm - 0.8 * 0.8) / (1 - 0.8 * 0.8);
|
||||
// Same, simplified
|
||||
float oneDistNorm = 1.0 - distNorm;
|
||||
att *= lerp(1.0, oneDistNorm * 2.78, step(0.64, distNorm));
|
||||
|
||||
att *= step(0.0, oneDistNorm);
|
||||
|
||||
return att;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
float Attenuation(float distSqr)
|
||||
{
|
||||
float d = sqrt(distSqr);
|
||||
float kDefaultPointLightRadius = 0.25;
|
||||
return 1.0 / pow(1.0 + d/kDefaultPointLightRadius, 2);
|
||||
}
|
||||
|
||||
float AttenuationToZero(float distSqr)
|
||||
{
|
||||
// attenuation = 1 / (1 + distance_to_light / light_radius)^2
|
||||
// = 1 / (1 + 2*(d/r) + (d/r)^2)
|
||||
// For more details see: https://imdoingitwrong.wordpress.com/2011/01/31/light-attenuation/
|
||||
float d = sqrt(distSqr);
|
||||
float kDefaultPointLightRadius = 0.25;
|
||||
float atten = 1.0 / pow(1.0 + d/kDefaultPointLightRadius, 2);
|
||||
float kCutoff = 1.0 / pow(1.0 + 1.0/kDefaultPointLightRadius, 2); // cutoff equal to attenuation at distance 1.0
|
||||
|
||||
// Force attenuation to fall towards zero at distance 1.0
|
||||
atten = (atten - kCutoff) / (1.f - kCutoff);
|
||||
if (d >= 1.f)
|
||||
atten = 0.f;
|
||||
|
||||
return atten;
|
||||
}
|
||||
|
||||
#endif
|
9
Assets/TubeLight/Shaders/TubeLightAttenuation.cginc.meta
Normal file
9
Assets/TubeLight/Shaders/TubeLightAttenuation.cginc.meta
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3d6df6428d576d147994b0b7ac0d5ea5
|
||||
timeCreated: 1456703457
|
||||
licenseType: Pro
|
||||
ShaderImporter:
|
||||
defaultTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
38
Assets/TubeLight/Shaders/TubeLightShadowPlanes.cginc
Normal file
38
Assets/TubeLight/Shaders/TubeLightShadowPlanes.cginc
Normal file
@ -0,0 +1,38 @@
|
||||
half ShadowPlane(half3 worldPos, half4 plane, half feather)
|
||||
{
|
||||
half x = plane.w - dot(worldPos, plane.xyz);
|
||||
// Compiler bug workaround
|
||||
x += 0.0001;
|
||||
return smoothstep(-feather, feather, x);
|
||||
}
|
||||
|
||||
float4 _ShadowPlane0;
|
||||
float _ShadowPlaneFeather0;
|
||||
float4 _ShadowPlane1;
|
||||
float _ShadowPlaneFeather1;
|
||||
|
||||
half ShadowPlanes(half3 worldPos)
|
||||
{
|
||||
half att = 1;
|
||||
att *= ShadowPlane(worldPos, _ShadowPlane0, _ShadowPlaneFeather0);
|
||||
att *= ShadowPlane(worldPos, _ShadowPlane1, _ShadowPlaneFeather1);
|
||||
return att;
|
||||
}
|
||||
|
||||
struct TubeLightShadowPlane
|
||||
{
|
||||
float4 plane0;
|
||||
float4 plane1;
|
||||
float feather0;
|
||||
float feather1;
|
||||
float padding0;
|
||||
float padding1;
|
||||
};
|
||||
|
||||
half ShadowPlanes(half3 worldPos, TubeLightShadowPlane params)
|
||||
{
|
||||
half att = 1;
|
||||
att *= ShadowPlane(worldPos, params.plane0, params.feather0);
|
||||
att *= ShadowPlane(worldPos, params.plane1, params.feather1);
|
||||
return att;
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f4ec63bd62722b840b982641528198db
|
||||
timeCreated: 1457385992
|
||||
licenseType: Pro
|
||||
ShaderImporter:
|
||||
defaultTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
190
Assets/TubeLight/Shaders/TubeLightSource.mat
Normal file
190
Assets/TubeLight/Shaders/TubeLightSource.mat
Normal file
@ -0,0 +1,190 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 0}
|
||||
m_Name: TubeLightSource
|
||||
m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_ShaderKeywords: _EMISSION
|
||||
m_LightmapFlags: 0
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap: {}
|
||||
m_SavedProperties:
|
||||
serializedVersion: 2
|
||||
m_TexEnvs:
|
||||
- first:
|
||||
name: _BumpMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- first:
|
||||
name: _DetailAlbedoMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- first:
|
||||
name: _DetailMask
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- first:
|
||||
name: _DetailNormalMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- first:
|
||||
name: _EmissionMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- first:
|
||||
name: _MainTex
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- first:
|
||||
name: _MetallicGlossMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- first:
|
||||
name: _OcclusionMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- first:
|
||||
name: _ParallaxMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- first:
|
||||
name: _SpecGlossMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Floats:
|
||||
- first:
|
||||
name: _BumpScale
|
||||
second: 1
|
||||
- first:
|
||||
name: _CullMode
|
||||
second: 2
|
||||
- first:
|
||||
name: _Cutoff
|
||||
second: 0.5
|
||||
- first:
|
||||
name: _DetailMode
|
||||
second: 0
|
||||
- first:
|
||||
name: _DetailNormalMapScale
|
||||
second: 1
|
||||
- first:
|
||||
name: _DstBlend
|
||||
second: 0
|
||||
- first:
|
||||
name: _GlossMapScale
|
||||
second: 1
|
||||
- first:
|
||||
name: _Glossiness
|
||||
second: 0.234
|
||||
- first:
|
||||
name: _GlossyReflections
|
||||
second: 1
|
||||
- first:
|
||||
name: _LightProbeScale
|
||||
second: 1
|
||||
- first:
|
||||
name: _MetaDiffuseScale
|
||||
second: 1
|
||||
- first:
|
||||
name: _MetaEmissionScale
|
||||
second: 1
|
||||
- first:
|
||||
name: _MetaMetallicSoup
|
||||
second: 1
|
||||
- first:
|
||||
name: _MetaSpecularScale
|
||||
second: 1
|
||||
- first:
|
||||
name: _MetaUseCustom
|
||||
second: 0
|
||||
- first:
|
||||
name: _Metallic
|
||||
second: 0
|
||||
- first:
|
||||
name: _Mode
|
||||
second: 0
|
||||
- first:
|
||||
name: _OcclusionStrength
|
||||
second: 1
|
||||
- first:
|
||||
name: _Parallax
|
||||
second: 0.02
|
||||
- first:
|
||||
name: _ReflectionProbeBoost
|
||||
second: 1
|
||||
- first:
|
||||
name: _SmoothnessTextureChannel
|
||||
second: 0
|
||||
- first:
|
||||
name: _SpecularHighlights
|
||||
second: 1
|
||||
- first:
|
||||
name: _SrcBlend
|
||||
second: 1
|
||||
- first:
|
||||
name: _Translucency
|
||||
second: 0
|
||||
- first:
|
||||
name: _UVDetailMask
|
||||
second: 0
|
||||
- first:
|
||||
name: _UVSec
|
||||
second: 0
|
||||
- first:
|
||||
name: _VertexOcclusionPower
|
||||
second: 1
|
||||
- first:
|
||||
name: _ZWrite
|
||||
second: 1
|
||||
m_Colors:
|
||||
- first:
|
||||
name: _Color
|
||||
second: {r: 0.47794116, g: 1, b: 0.85685486, a: 1}
|
||||
- first:
|
||||
name: _EmissionColor
|
||||
second: {r: 1, g: 1, b: 1, a: 1}
|
||||
- first:
|
||||
name: _MetaDiffuseAdd
|
||||
second: {r: 0, g: 0, b: 0, a: 1}
|
||||
- first:
|
||||
name: _MetaDiffuseTint
|
||||
second: {r: 1, g: 1, b: 1, a: 1}
|
||||
- first:
|
||||
name: _MetaEmissionAdd
|
||||
second: {r: 0, g: 0, b: 0, a: 1}
|
||||
- first:
|
||||
name: _MetaEmissionTint
|
||||
second: {r: 1, g: 1, b: 1, a: 1}
|
||||
- first:
|
||||
name: _MetaSpecularAdd
|
||||
second: {r: 0, g: 0, b: 0, a: 1}
|
||||
- first:
|
||||
name: _MetaSpecularTint
|
||||
second: {r: 1, g: 1, b: 1, a: 1}
|
||||
- first:
|
||||
name: _SpecColor
|
||||
second: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
|
8
Assets/TubeLight/Shaders/TubeLightSource.mat.meta
Normal file
8
Assets/TubeLight/Shaders/TubeLightSource.mat.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 86b3c638dc56298409890ac32f9e6baf
|
||||
timeCreated: 1446644410
|
||||
licenseType: Pro
|
||||
NativeFormatImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
180
Assets/TubeLight/TubeLight.prefab
Normal file
180
Assets/TubeLight/TubeLight.prefab
Normal file
@ -0,0 +1,180 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &154090
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
serializedVersion: 4
|
||||
m_Component:
|
||||
- 4: {fileID: 466162}
|
||||
- 114: {fileID: 11466842}
|
||||
- 33: {fileID: 3327276}
|
||||
- 23: {fileID: 2315154}
|
||||
- 114: {fileID: 114000012794840980}
|
||||
m_Layer: 0
|
||||
m_Name: TubeLight
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &466162
|
||||
Transform:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 154090}
|
||||
m_LocalRotation: {x: -0.7071068, y: 0, z: 0, w: 0.7071067}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
--- !u!23 &2315154
|
||||
MeshRenderer:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 154090}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 0
|
||||
m_ReceiveShadows: 0
|
||||
m_MotionVectors: 1
|
||||
m_LightProbeUsage: 0
|
||||
m_ReflectionProbeUsage: 0
|
||||
m_Materials:
|
||||
- {fileID: 2100000, guid: 86b3c638dc56298409890ac32f9e6baf, type: 2}
|
||||
m_SubsetIndices:
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_PreserveUVs: 0
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_SelectedWireframeHidden: 0
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_SortingLayerID: 0
|
||||
m_SortingOrder: 0
|
||||
--- !u!33 &3327276
|
||||
MeshFilter:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 154090}
|
||||
m_Mesh: {fileID: 0}
|
||||
--- !u!114 &11466842
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 154090}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5a3b99ed98424ea4587ec18d930a1d77, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Intensity: 0.8
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_Range: 10
|
||||
m_Radius: 0.3
|
||||
m_Length: 0
|
||||
m_Sphere: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0}
|
||||
m_Capsule: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0}
|
||||
m_ProxyShader: {fileID: 4800000, guid: 2e6fd90941a3e3c458d01f851dca21ed, type: 3}
|
||||
m_RenderSource: 1
|
||||
m_ShadowPlanes:
|
||||
- {fileID: 0}
|
||||
- {fileID: 0}
|
||||
--- !u!1001 &100100000
|
||||
Prefab:
|
||||
m_ObjectHideFlags: 1
|
||||
serializedVersion: 2
|
||||
m_Modification:
|
||||
m_TransformParent: {fileID: 0}
|
||||
m_Modifications:
|
||||
- target: {fileID: 0}
|
||||
propertyPath: m_RenderSource
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 0}
|
||||
propertyPath: m_Radius
|
||||
value: .340000004
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 0}
|
||||
propertyPath: m_Length
|
||||
value: .649999976
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 0}
|
||||
propertyPath: m_LocalRotation.x
|
||||
value: -.707106829
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 0}
|
||||
propertyPath: m_LocalRotation.w
|
||||
value: .707106709
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 0}
|
||||
propertyPath: m_LocalPosition.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 0}
|
||||
propertyPath: m_LocalPosition.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 0}
|
||||
propertyPath: m_LocalPosition.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 0}
|
||||
propertyPath: m_CastShadows
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 0}
|
||||
propertyPath: m_ReceiveShadows
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 0}
|
||||
propertyPath: m_UseLightProbes
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 0}
|
||||
propertyPath: m_ReflectionProbeUsage
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 0}
|
||||
propertyPath: m_Materials.Array.data[0]
|
||||
value:
|
||||
objectReference: {fileID: 2100000, guid: 86b3c638dc56298409890ac32f9e6baf, type: 2}
|
||||
m_RemovedComponents: []
|
||||
m_ParentPrefab: {fileID: 0}
|
||||
m_RootGameObject: {fileID: 154090}
|
||||
m_IsPrefabParent: 1
|
||||
--- !u!114 &114000012794840980
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 154090}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 097385f2a510795498370c4d62e61572, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_IntensityMult: 1
|
||||
m_RangeMult: 1
|
||||
m_BlurShadowmapShader: {fileID: 4800000, guid: 701192b62a7678549918bc87434699fe,
|
||||
type: 3}
|
||||
m_CopyShadowParamsShader: {fileID: 4800000, guid: 33fc45db43408764c8dd7647b877e561,
|
||||
type: 3}
|
||||
m_ForceOnForFog: 0
|
||||
m_Shadows: 0
|
||||
m_ShadowmapRes: 256
|
||||
m_BlurIterations: 0
|
||||
m_BlurSize: 1
|
||||
m_ESMExponent: 40
|
||||
m_Bounded: 1
|
8
Assets/TubeLight/TubeLight.prefab.meta
Normal file
8
Assets/TubeLight/TubeLight.prefab.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fdeb35bdab08b7442a67e36ffe2ff830
|
||||
timeCreated: 1444651113
|
||||
licenseType: Pro
|
||||
NativeFormatImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
9
Assets/VolumetricFog.meta
Normal file
9
Assets/VolumetricFog.meta
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 40bc07addad39024a9ef54e341a25a68
|
||||
folderAsset: yes
|
||||
timeCreated: 1476957694
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
9
Assets/VolumetricFog/Editor.meta
Normal file
9
Assets/VolumetricFog/Editor.meta
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9d612dacdb3ca214c9322d7f9c288f22
|
||||
folderAsset: yes
|
||||
timeCreated: 1457126022
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
73
Assets/VolumetricFog/Editor/FogLightEditor.cs
Normal file
73
Assets/VolumetricFog/Editor/FogLightEditor.cs
Normal file
@ -0,0 +1,73 @@
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
[CustomEditor(typeof(FogLight))]
|
||||
[CanEditMultipleObjects]
|
||||
public class FogLightEditor : Editor
|
||||
{
|
||||
SerializedProperty m_IntensityMult;
|
||||
SerializedProperty m_RangeMult;
|
||||
SerializedProperty m_ForceOnForFog;
|
||||
SerializedProperty m_Shadows;
|
||||
SerializedProperty m_ShadowmapRes;
|
||||
SerializedProperty m_BlurIterations;
|
||||
SerializedProperty m_BlurSize;
|
||||
SerializedProperty m_Bounded;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
m_IntensityMult = serializedObject.FindProperty ("m_IntensityMult");
|
||||
m_RangeMult = serializedObject.FindProperty ("m_RangeMult");
|
||||
m_ForceOnForFog = serializedObject.FindProperty ("m_ForceOnForFog");
|
||||
m_Shadows = serializedObject.FindProperty ("m_Shadows");
|
||||
m_ShadowmapRes = serializedObject.FindProperty ("m_ShadowmapRes");
|
||||
m_BlurIterations = serializedObject.FindProperty ("m_BlurIterations");
|
||||
m_BlurSize = serializedObject.FindProperty ("m_BlurSize");
|
||||
m_Bounded = serializedObject.FindProperty("m_Bounded");
|
||||
}
|
||||
|
||||
override public void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUILayout.PropertyField(m_IntensityMult);
|
||||
EditorGUILayout.PropertyField(m_RangeMult);
|
||||
EditorGUILayout.PropertyField(m_ForceOnForFog);
|
||||
|
||||
// Section below just for light types with shadow
|
||||
bool supportsShadows = false;
|
||||
bool isAreaLight = false;
|
||||
foreach (FogLight fogLight in targets)
|
||||
{
|
||||
if (fogLight.type == FogLight.Type.Area)
|
||||
{
|
||||
supportsShadows = true;
|
||||
isAreaLight = true;
|
||||
break;
|
||||
}
|
||||
else if (fogLight.type == FogLight.Type.Directional)
|
||||
{
|
||||
supportsShadows = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (supportsShadows)
|
||||
{
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.PropertyField(m_Shadows);
|
||||
EditorGUILayout.PropertyField(m_ShadowmapRes);
|
||||
EditorGUILayout.PropertyField(m_BlurIterations);
|
||||
EditorGUILayout.PropertyField(m_BlurSize);
|
||||
}
|
||||
|
||||
if (isAreaLight)
|
||||
{
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.PropertyField(m_Bounded);
|
||||
}
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
12
Assets/VolumetricFog/Editor/FogLightEditor.cs.meta
Normal file
12
Assets/VolumetricFog/Editor/FogLightEditor.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 93f87826f4342d7448c226b220a4342e
|
||||
timeCreated: 1457126034
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
54
Assets/VolumetricFog/FogEllipsoid.prefab
Normal file
54
Assets/VolumetricFog/FogEllipsoid.prefab
Normal file
@ -0,0 +1,54 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &141782
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
serializedVersion: 4
|
||||
m_Component:
|
||||
- 4: {fileID: 463416}
|
||||
- 114: {fileID: 11477592}
|
||||
m_Layer: 0
|
||||
m_Name: FogEllipsoid
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &463416
|
||||
Transform:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 141782}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
--- !u!114 &11477592
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 141782}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 789ae5fef74e6754ab3c20bdeca67ad9, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Radius: 1
|
||||
m_Stretch: 2
|
||||
--- !u!1001 &100100000
|
||||
Prefab:
|
||||
m_ObjectHideFlags: 1
|
||||
serializedVersion: 2
|
||||
m_Modification:
|
||||
m_TransformParent: {fileID: 0}
|
||||
m_Modifications: []
|
||||
m_RemovedComponents: []
|
||||
m_ParentPrefab: {fileID: 0}
|
||||
m_RootGameObject: {fileID: 141782}
|
||||
m_IsPrefabParent: 1
|
8
Assets/VolumetricFog/FogEllipsoid.prefab.meta
Normal file
8
Assets/VolumetricFog/FogEllipsoid.prefab.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: df830a50a2bb02541a47504c9da3b3cf
|
||||
timeCreated: 1447329149
|
||||
licenseType: Pro
|
||||
NativeFormatImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
9
Assets/VolumetricFog/Scripts.meta
Normal file
9
Assets/VolumetricFog/Scripts.meta
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dcf5e0fc0fb8d64458536282eee32001
|
||||
folderAsset: yes
|
||||
timeCreated: 1477748633
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
59
Assets/VolumetricFog/Scripts/FogEllipsoid.cs
Normal file
59
Assets/VolumetricFog/Scripts/FogEllipsoid.cs
Normal file
@ -0,0 +1,59 @@
|
||||
using UnityEngine;
|
||||
|
||||
[ExecuteInEditMode]
|
||||
public class FogEllipsoid : MonoBehaviour
|
||||
{
|
||||
public enum Blend
|
||||
{
|
||||
Additive,
|
||||
Multiplicative
|
||||
}
|
||||
|
||||
public Blend m_Blend = Blend.Additive;
|
||||
public float m_Density = 1.0f;
|
||||
[MinValue(0)]
|
||||
public float m_Radius = 1.0f;
|
||||
[MinValue(0)]
|
||||
public float m_Stretch = 2.0f;
|
||||
[Range(0, 1)]
|
||||
public float m_Feather = 0.7f;
|
||||
[Range(0, 1)]
|
||||
public float m_NoiseAmount = 0.0f;
|
||||
public float m_NoiseSpeed = 1.0f;
|
||||
[MinValue(0)]
|
||||
public float m_NoiseScale = 1.0f;
|
||||
|
||||
bool m_AddedToLightManager = false;
|
||||
|
||||
void AddToLightManager()
|
||||
{
|
||||
if (!m_AddedToLightManager)
|
||||
m_AddedToLightManager = LightManagerFogEllipsoids.Add(this);
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
AddToLightManager();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
// LightManager might not have been available during this light's OnEnable(), so keep trying.
|
||||
AddToLightManager();
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
LightManagerFogEllipsoids.Remove(this);
|
||||
m_AddedToLightManager = false;
|
||||
}
|
||||
|
||||
void OnDrawGizmosSelected()
|
||||
{
|
||||
Matrix4x4 m = Matrix4x4.identity;
|
||||
Transform t = transform;
|
||||
m.SetTRS(t.position, t.rotation, new Vector3(1.0f, m_Stretch, 1.0f));
|
||||
Gizmos.matrix = m;
|
||||
Gizmos.DrawWireSphere(Vector3.zero, m_Radius);
|
||||
}
|
||||
}
|
12
Assets/VolumetricFog/Scripts/FogEllipsoid.cs.meta
Normal file
12
Assets/VolumetricFog/Scripts/FogEllipsoid.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 789ae5fef74e6754ab3c20bdeca67ad9
|
||||
timeCreated: 1447327681
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
157
Assets/VolumetricFog/Scripts/FogLight.DirectionalShadow.cs
Normal file
157
Assets/VolumetricFog/Scripts/FogLight.DirectionalShadow.cs
Normal file
@ -0,0 +1,157 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
public partial class FogLight : LightOverride
|
||||
{
|
||||
CommandBuffer m_BufGrabShadowmap;
|
||||
CommandBuffer m_BufGrabShadowParams;
|
||||
RenderTexture m_Shadowmap;
|
||||
|
||||
ComputeBuffer m_ShadowParamsCB;
|
||||
//[HideInInspector]
|
||||
public Shader m_BlurShadowmapShader;
|
||||
Material m_BlurShadowmapMaterial;
|
||||
|
||||
public Shader m_CopyShadowParamsShader;
|
||||
Material m_CopyShadowParamsMaterial;
|
||||
|
||||
bool directionalShadow {get{ return m_Shadows && type == Type.Directional; }}
|
||||
|
||||
void InitDirectionalShadowmap()
|
||||
{
|
||||
if (m_BufGrabShadowmap != null || !directionalShadow)
|
||||
return;
|
||||
|
||||
Light light = GetComponent<Light>();
|
||||
|
||||
m_BufGrabShadowmap = new CommandBuffer();
|
||||
m_BufGrabShadowmap.name = "Grab shadowmap for Volumetric Fog";
|
||||
light.AddCommandBuffer(LightEvent.AfterShadowMap, m_BufGrabShadowmap);
|
||||
|
||||
m_BufGrabShadowParams = new CommandBuffer();
|
||||
m_BufGrabShadowParams.name = "Grab shadow params for Volumetric Fog";
|
||||
light.AddCommandBuffer(LightEvent.BeforeScreenspaceMask, m_BufGrabShadowParams);
|
||||
|
||||
m_BlurShadowmapMaterial = new Material(m_BlurShadowmapShader);
|
||||
m_BlurShadowmapMaterial.hideFlags = HideFlags.HideAndDontSave;
|
||||
|
||||
m_CopyShadowParamsMaterial = new Material(m_CopyShadowParamsShader);
|
||||
m_CopyShadowParamsMaterial.hideFlags = HideFlags.HideAndDontSave;
|
||||
}
|
||||
|
||||
int[] temp;
|
||||
|
||||
public void UpdateDirectionalShadowmap()
|
||||
{
|
||||
InitDirectionalShadowmap();
|
||||
|
||||
if (m_BufGrabShadowmap != null)
|
||||
m_BufGrabShadowmap.Clear();
|
||||
if (m_BufGrabShadowParams != null)
|
||||
m_BufGrabShadowParams.Clear();
|
||||
|
||||
if (!directionalShadow)
|
||||
return;
|
||||
|
||||
// Copy directional shadowmap params - they're only set for regular shaders, but we need them in compute
|
||||
if (m_ShadowParamsCB == null)
|
||||
m_ShadowParamsCB = new ComputeBuffer(1, 336);
|
||||
Graphics.SetRandomWriteTarget(2, m_ShadowParamsCB);
|
||||
m_BufGrabShadowParams.DrawProcedural(Matrix4x4.identity, m_CopyShadowParamsMaterial, 0, MeshTopology.Points, 1);
|
||||
|
||||
// TODO: get the real size of the shadowmap
|
||||
int startRes = 4096;
|
||||
// To make things easier, blurred shadowmap is at most half the size of the regular.
|
||||
int targetRes = Mathf.Min((int)m_ShadowmapRes, startRes/2);
|
||||
int downsampleSteps = (int)Mathf.Log(startRes / targetRes, 2);
|
||||
|
||||
RenderTargetIdentifier shadowmap = BuiltinRenderTextureType.CurrentActive;
|
||||
m_BufGrabShadowmap.SetShadowSamplingMode(shadowmap, ShadowSamplingMode.RawDepth);
|
||||
|
||||
// RFloat for ESM, RGHalf for VSM
|
||||
RenderTextureFormat format = RenderTextureFormat.RGHalf;
|
||||
|
||||
ReleaseTemporary(ref m_Shadowmap);
|
||||
m_Shadowmap = RenderTexture.GetTemporary(targetRes, targetRes, 0, format, RenderTextureReadWrite.Linear);
|
||||
m_Shadowmap.filterMode = FilterMode.Bilinear;
|
||||
m_Shadowmap.wrapMode = TextureWrapMode.Clamp;
|
||||
|
||||
if (temp == null || temp.Length != downsampleSteps - 1)
|
||||
temp = new int[downsampleSteps - 1];
|
||||
|
||||
for (int i = 0, currentRes = startRes/2; i < downsampleSteps; i++)
|
||||
{
|
||||
m_BufGrabShadowmap.SetGlobalVector("_TexelSize", new Vector4(0.5f/currentRes, 0.5f/currentRes, 0, 0));
|
||||
|
||||
RenderTargetIdentifier targetRT;
|
||||
|
||||
if (i < downsampleSteps - 1)
|
||||
{
|
||||
temp[i] = Shader.PropertyToID("ShadowmapDownscaleTemp" + i);
|
||||
m_BufGrabShadowmap.GetTemporaryRT(temp[i], currentRes, currentRes, 0, FilterMode.Bilinear, format, RenderTextureReadWrite.Linear);
|
||||
targetRT = new RenderTargetIdentifier(temp[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Last step: write into the shadowmap texture
|
||||
targetRT = new RenderTargetIdentifier(m_Shadowmap);
|
||||
}
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
// This step should convert to ESM/VSM
|
||||
// m_BufGrabShadowmap.Blit(shadowmap, targetRT);
|
||||
m_BufGrabShadowmap.SetGlobalTexture("_DirShadowmap", shadowmap);
|
||||
m_BufGrabShadowmap.Blit(null, targetRT, m_BlurShadowmapMaterial, /*sample & convert to VSM*/ 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_BufGrabShadowmap.Blit(temp[i - 1], targetRT, m_BlurShadowmapMaterial, /*regular sample*/ 5);
|
||||
}
|
||||
|
||||
currentRes /= 2;
|
||||
}
|
||||
|
||||
//var directionalShadowmapBlurred = Shader.PropertyToID("_DirectionalShadowmapBlurred");
|
||||
//m_BufGrabShadowmap.GetTemporaryRT(directionalShadowmapBlurred, 1024, 1024, 0, FilterMode.Bilinear, RenderTextureFormat.RFloat, RenderTextureReadWrite.Linear);
|
||||
//m_BufGrabShadowmap.Blit(shadowmap, m_Shadowmap);
|
||||
//m_BufGrabShadowmap.SetGlobalTexture(directionalShadowmapBlurred, directionalShadowmapBlurred);
|
||||
}
|
||||
|
||||
void CleanupDirectionalShadowmap()
|
||||
{
|
||||
if (m_BufGrabShadowmap != null)
|
||||
m_BufGrabShadowmap.Clear();
|
||||
|
||||
if (m_BufGrabShadowParams != null)
|
||||
m_BufGrabShadowParams.Clear();
|
||||
|
||||
if(m_ShadowParamsCB != null)
|
||||
m_ShadowParamsCB.Release();
|
||||
m_ShadowParamsCB = null;
|
||||
}
|
||||
|
||||
public bool SetUpDirectionalShadowmapForSampling(bool shadows, ComputeShader cs, int kernel)
|
||||
{
|
||||
if (!shadows || m_ShadowParamsCB == null || m_Shadowmap == null)
|
||||
{
|
||||
cs.SetFloat("_DirLightShadows", 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
cs.SetFloat("_DirLightShadows", 1);
|
||||
cs.SetBuffer(kernel, "_ShadowParams", m_ShadowParamsCB);
|
||||
cs.SetTexture(kernel, "_DirectionalShadowmap", m_Shadowmap);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ReleaseTemporary(ref RenderTexture rt)
|
||||
{
|
||||
if (rt == null)
|
||||
return;
|
||||
|
||||
RenderTexture.ReleaseTemporary(rt);
|
||||
rt = null;
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f567a9d3b2b31ac4d818cea1e427a215
|
||||
timeCreated: 1460031458
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
60
Assets/VolumetricFog/Scripts/FogLight.cs
Normal file
60
Assets/VolumetricFog/Scripts/FogLight.cs
Normal file
@ -0,0 +1,60 @@
|
||||
using UnityEngine;
|
||||
|
||||
[ExecuteInEditMode]
|
||||
public partial class FogLight : LightOverride
|
||||
{
|
||||
public bool m_ForceOnForFog = false;
|
||||
[Tooltip("Only one shadowed fog AreaLight at a time.")]
|
||||
[Header("Shadows")]
|
||||
public bool m_Shadows = false;
|
||||
|
||||
public enum TextureSize
|
||||
{
|
||||
x256 = 256,
|
||||
x512 = 512,
|
||||
x1024 = 1024,
|
||||
}
|
||||
|
||||
[Tooltip("Always at most half the res of the AreaLight's shadowmap.")]
|
||||
public TextureSize m_ShadowmapRes = TextureSize.x256;
|
||||
[Range(0, 3)]
|
||||
public int m_BlurIterations = 0;
|
||||
[MinValue(0)]
|
||||
public float m_BlurSize = 1.0f;
|
||||
[MinValue(0)]
|
||||
[Tooltip("Affects shadow softness.")]
|
||||
public float m_ESMExponent = 40.0f;
|
||||
|
||||
public bool m_Bounded = true;
|
||||
|
||||
public override bool GetForceOn()
|
||||
{
|
||||
return m_ForceOnForFog;
|
||||
}
|
||||
|
||||
bool m_AddedToLightManager = false;
|
||||
|
||||
void AddToLightManager()
|
||||
{
|
||||
if (!m_AddedToLightManager)
|
||||
m_AddedToLightManager = LightManagerFogLights.Add(this);
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
AddToLightManager();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
// LightManager might not have been available during this light's OnEnable(), so keep trying.
|
||||
AddToLightManager();
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
LightManagerFogLights.Remove(this);
|
||||
m_AddedToLightManager = false;
|
||||
CleanupDirectionalShadowmap();
|
||||
}
|
||||
}
|
16
Assets/VolumetricFog/Scripts/FogLight.cs.meta
Normal file
16
Assets/VolumetricFog/Scripts/FogLight.cs.meta
Normal file
@ -0,0 +1,16 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 097385f2a510795498370c4d62e61572
|
||||
timeCreated: 1463313191
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences:
|
||||
- m_BlurShadowmapShader: {fileID: 4800000, guid: 701192b62a7678549918bc87434699fe,
|
||||
type: 3}
|
||||
- m_CopyShadowParamsShader: {fileID: 4800000, guid: 33fc45db43408764c8dd7647b877e561,
|
||||
type: 3}
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
719
Assets/VolumetricFog/Scripts/VolumetricFog.cs
Normal file
719
Assets/VolumetricFog/Scripts/VolumetricFog.cs
Normal file
@ -0,0 +1,719 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
using System.Collections.Generic;
|
||||
|
||||
[ExecuteInEditMode]
|
||||
[RequireComponent (typeof(Camera))]
|
||||
public class VolumetricFog : MonoBehaviour
|
||||
{
|
||||
Material m_DebugMaterial;
|
||||
[HideInInspector]
|
||||
public Shader m_DebugShader;
|
||||
[HideInInspector]
|
||||
public Shader m_ShadowmapShader;
|
||||
[HideInInspector]
|
||||
public ComputeShader m_InjectLightingAndDensity;
|
||||
[HideInInspector]
|
||||
public ComputeShader m_Scatter;
|
||||
Material m_ApplyToOpaqueMaterial;
|
||||
[HideInInspector]
|
||||
public Shader m_ApplyToOpaqueShader;
|
||||
Material m_BlurShadowmapMaterial;
|
||||
[HideInInspector]
|
||||
public Shader m_BlurShadowmapShader;
|
||||
[HideInInspector]
|
||||
public Texture2D m_Noise;
|
||||
[HideInInspector]
|
||||
public bool m_Debug = false;
|
||||
[HideInInspector]
|
||||
[Range(0.0f, 1.0f)]
|
||||
public float m_Z = 1.0f;
|
||||
|
||||
[Header("Size")]
|
||||
[MinValue(0.1f)]
|
||||
public float m_NearClip = 0.1f;
|
||||
[MinValue(0.1f)]
|
||||
public float m_FarClipMax = 100.0f;
|
||||
|
||||
[Header("Fog Density")]
|
||||
[FormerlySerializedAs("m_Density")]
|
||||
public float m_GlobalDensityMult = 1.0f;
|
||||
Vector3i m_InjectNumThreads = new Vector3i(16, 2, 16);
|
||||
Vector3i m_ScatterNumThreads = new Vector3i(32, 2, 1);
|
||||
RenderTexture m_VolumeInject;
|
||||
RenderTexture m_VolumeScatter;
|
||||
Vector3i m_VolumeResolution = new Vector3i(160, 90, 128);
|
||||
Camera m_Camera;
|
||||
Camera m_ShadowmapCamera;
|
||||
RenderTexture m_Shadowmap;
|
||||
RenderTexture m_ShadowmapBlurred;
|
||||
int m_ShadowmapRes = 1024;
|
||||
|
||||
// Density
|
||||
public float m_ConstantFog = 0;
|
||||
public float m_HeightFogAmount = 0;
|
||||
public float m_HeightFogExponent = 0;
|
||||
public float m_HeightFogOffset = 0;
|
||||
|
||||
[Tooltip("Noise multiplies with constant fog and height fog, but not with fog ellipsoids.")]
|
||||
[Range(0.0f, 1.0f)]
|
||||
public float m_NoiseFogAmount = 0;
|
||||
public float m_NoiseFogScale = 1;
|
||||
public Wind m_Wind;
|
||||
|
||||
[Range(0.0f, 0.999f)]
|
||||
public float m_Anisotropy = 0.0f;
|
||||
|
||||
[Header("Lights")]
|
||||
[FormerlySerializedAs("m_Intensity")]
|
||||
public float m_GlobalIntensityMult = 1.0f;
|
||||
[MinValue(0)]
|
||||
public float m_AmbientLightIntensity = 0.0f;
|
||||
public Color m_AmbientLightColor = Color.white;
|
||||
|
||||
[HideInInspector]
|
||||
public bool m_BlurShadowmap = false;
|
||||
[HideInInspector]
|
||||
[Range(0, 2)]
|
||||
public int m_ShadowmapDownsample = 1;
|
||||
[HideInInspector]
|
||||
[Range(0.0f, 10.0f)]
|
||||
public float m_BlurSize = 3.0f;
|
||||
[HideInInspector]
|
||||
[Range(1, 4)]
|
||||
public int m_BlurIterations = 2;
|
||||
|
||||
struct Vector3i
|
||||
{
|
||||
public int x, y, z;
|
||||
public Vector3i(int x, int y, int z)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
}
|
||||
|
||||
struct PointLightParams
|
||||
{
|
||||
public Vector3 pos;
|
||||
public float range;
|
||||
public Vector3 color;
|
||||
float padding;
|
||||
}
|
||||
|
||||
PointLightParams[] m_PointLightParams;
|
||||
ComputeBuffer m_PointLightParamsCB;
|
||||
|
||||
struct TubeLightParams
|
||||
{
|
||||
public Vector3 start;
|
||||
public float range;
|
||||
public Vector3 end;
|
||||
public float radius;
|
||||
public Vector3 color;
|
||||
float padding;
|
||||
}
|
||||
|
||||
TubeLightParams[] m_TubeLightParams;
|
||||
ComputeBuffer m_TubeLightParamsCB;
|
||||
|
||||
struct TubeLightShadowPlaneParams
|
||||
{
|
||||
public Vector4 plane0;
|
||||
public Vector4 plane1;
|
||||
public float feather0;
|
||||
public float feather1;
|
||||
float padding0;
|
||||
float padding1;
|
||||
}
|
||||
|
||||
TubeLightShadowPlaneParams[] m_TubeLightShadowPlaneParams;
|
||||
ComputeBuffer m_TubeLightShadowPlaneParamsCB;
|
||||
|
||||
struct AreaLightParams
|
||||
{
|
||||
public Matrix4x4 mat;
|
||||
public Vector4 pos;
|
||||
public Vector3 color;
|
||||
public float bounded;
|
||||
}
|
||||
|
||||
AreaLightParams[] m_AreaLightParams;
|
||||
ComputeBuffer m_AreaLightParamsCB;
|
||||
|
||||
struct FogEllipsoidParams
|
||||
{
|
||||
public Vector3 pos;
|
||||
public float radius;
|
||||
public Vector3 axis;
|
||||
public float stretch;
|
||||
public float density;
|
||||
public float noiseAmount;
|
||||
public float noiseSpeed;
|
||||
public float noiseScale;
|
||||
public float feather;
|
||||
public float blend;
|
||||
public float padding1;
|
||||
public float padding2;
|
||||
}
|
||||
|
||||
FogEllipsoidParams[] m_FogEllipsoidParams;
|
||||
ComputeBuffer m_FogEllipsoidParamsCB;
|
||||
|
||||
Camera cam{ get { if (m_Camera == null) m_Camera = GetComponent<Camera>(); return m_Camera; }}
|
||||
|
||||
float nearClip { get { return Mathf.Max(0, m_NearClip); } }
|
||||
float farClip { get { return Mathf.Min(cam.farClipPlane, m_FarClipMax); } }
|
||||
|
||||
void ReleaseComputeBuffer(ref ComputeBuffer buffer)
|
||||
{
|
||||
if(buffer != null)
|
||||
buffer.Release();
|
||||
buffer = null;
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
void Cleanup()
|
||||
{
|
||||
DestroyImmediate(m_VolumeInject);
|
||||
DestroyImmediate(m_VolumeScatter);
|
||||
ReleaseComputeBuffer(ref m_PointLightParamsCB);
|
||||
ReleaseComputeBuffer(ref m_TubeLightParamsCB);
|
||||
ReleaseComputeBuffer(ref m_TubeLightShadowPlaneParamsCB);
|
||||
ReleaseComputeBuffer(ref m_AreaLightParamsCB);
|
||||
ReleaseComputeBuffer(ref m_FogEllipsoidParamsCB);
|
||||
m_VolumeInject = null;
|
||||
m_VolumeScatter = null;
|
||||
}
|
||||
|
||||
void SanitizeInput()
|
||||
{
|
||||
m_GlobalDensityMult = Mathf.Max(m_GlobalDensityMult, 0);
|
||||
m_ConstantFog = Mathf.Max(m_ConstantFog, 0);
|
||||
m_HeightFogAmount = Mathf.Max(m_HeightFogAmount, 0);
|
||||
}
|
||||
|
||||
void SetUpPointLightBuffers(int kernel)
|
||||
{
|
||||
int count = m_PointLightParamsCB == null ? 0 : m_PointLightParamsCB.count;
|
||||
m_InjectLightingAndDensity.SetFloat("_PointLightsCount", count);
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
if (m_PointLightParams == null || m_PointLightParams.Length != count)
|
||||
m_PointLightParams = new PointLightParams[count];
|
||||
|
||||
HashSet<FogLight> fogLights = LightManagerFogLights.Get();
|
||||
|
||||
int j = 0;
|
||||
for (var x = fogLights.GetEnumerator(); x.MoveNext();)
|
||||
{
|
||||
var fl = x.Current;
|
||||
if (fl == null || fl.type != FogLight.Type.Point || !fl.isOn)
|
||||
continue;
|
||||
|
||||
Light light = fl.light;
|
||||
m_PointLightParams[j].pos = light.transform.position;
|
||||
float range = light.range * fl.m_RangeMult;
|
||||
m_PointLightParams[j].range = 1.0f / (range * range);
|
||||
m_PointLightParams[j].color = new Vector3(light.color.r, light.color.g, light.color.b) * light.intensity * fl.m_IntensityMult;
|
||||
j++;
|
||||
}
|
||||
|
||||
// TODO: try a constant buffer with setfloats instead for perf
|
||||
m_PointLightParamsCB.SetData(m_PointLightParams);
|
||||
m_InjectLightingAndDensity.SetBuffer(kernel, "_PointLights", m_PointLightParamsCB);
|
||||
}
|
||||
|
||||
TubeLightShadowPlane.Params[] sppArr;
|
||||
|
||||
void SetUpTubeLightBuffers(int kernel)
|
||||
{
|
||||
int count = m_TubeLightParamsCB == null ? 0 : m_TubeLightParamsCB.count;
|
||||
m_InjectLightingAndDensity.SetFloat("_TubeLightsCount", count);
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
if (m_TubeLightParams == null || m_TubeLightParams.Length != count)
|
||||
m_TubeLightParams = new TubeLightParams[count];
|
||||
|
||||
if (m_TubeLightShadowPlaneParams == null || m_TubeLightShadowPlaneParams.Length != count)
|
||||
m_TubeLightShadowPlaneParams = new TubeLightShadowPlaneParams[count];
|
||||
|
||||
HashSet<FogLight> fogLights = LightManagerFogLights.Get();
|
||||
|
||||
int j = 0;
|
||||
for (var x = fogLights.GetEnumerator(); x.MoveNext();)
|
||||
{
|
||||
var fl = x.Current;
|
||||
if (fl == null || fl.type != FogLight.Type.Tube || !fl.isOn)
|
||||
continue;
|
||||
|
||||
TubeLight light = fl.tubeLight;
|
||||
Transform t = light.transform;
|
||||
Vector3 pos = t.position;
|
||||
Vector3 halfLength = 0.5f * t.up * light.m_Length;
|
||||
|
||||
// Tube lights
|
||||
m_TubeLightParams[j].start = pos + halfLength;
|
||||
m_TubeLightParams[j].end = pos - halfLength;
|
||||
float range = light.m_Range * fl.m_RangeMult;
|
||||
m_TubeLightParams[j].range = 1.0f / (range * range);
|
||||
m_TubeLightParams[j].color = new Vector3(light.m_Color.r, light.m_Color.g, light.m_Color.b) * light.m_Intensity * fl.m_IntensityMult;
|
||||
m_TubeLightParams[j].radius = light.m_Radius;
|
||||
|
||||
// Tube light shadow planes
|
||||
var p = light.GetShadowPlaneParams(ref sppArr);
|
||||
m_TubeLightShadowPlaneParams[j].plane0 = p[0].plane;
|
||||
m_TubeLightShadowPlaneParams[j].plane1 = p[1].plane;
|
||||
m_TubeLightShadowPlaneParams[j].feather0 = p[0].feather;
|
||||
m_TubeLightShadowPlaneParams[j].feather1 = p[1].feather;
|
||||
|
||||
j++;
|
||||
}
|
||||
|
||||
m_TubeLightParamsCB.SetData(m_TubeLightParams);
|
||||
m_InjectLightingAndDensity.SetBuffer(kernel, "_TubeLights", m_TubeLightParamsCB);
|
||||
m_TubeLightShadowPlaneParamsCB.SetData(m_TubeLightShadowPlaneParams);
|
||||
m_InjectLightingAndDensity.SetBuffer(kernel, "_TubeLightShadowPlanes", m_TubeLightShadowPlaneParamsCB);
|
||||
}
|
||||
|
||||
void SetUpAreaLightBuffers(int kernel)
|
||||
{
|
||||
int count = m_AreaLightParamsCB == null ? 0 : m_AreaLightParamsCB.count;
|
||||
m_InjectLightingAndDensity.SetFloat("_AreaLightsCount", count);
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
if (m_AreaLightParams == null || m_AreaLightParams.Length != count)
|
||||
m_AreaLightParams = new AreaLightParams[count];
|
||||
|
||||
HashSet<FogLight> fogLights = LightManagerFogLights.Get();
|
||||
|
||||
int shadowedAreaLightIndex = fogLights.Count;
|
||||
int j = 0;
|
||||
for (var x = fogLights.GetEnumerator(); x.MoveNext();)
|
||||
{
|
||||
var fl = x.Current;
|
||||
if (fl == null || fl.type != FogLight.Type.Area || !fl.isOn)
|
||||
continue;
|
||||
|
||||
AreaLight light = fl.areaLight;
|
||||
|
||||
m_AreaLightParams[j].mat = light.GetProjectionMatrix(true);
|
||||
m_AreaLightParams[j].pos = light.GetPosition();
|
||||
m_AreaLightParams[j].color = new Vector3(light.m_Color.r, light.m_Color.g, light.m_Color.b) * light.m_Intensity * fl.m_IntensityMult;
|
||||
m_AreaLightParams[j].bounded = fl.m_Bounded ? 1 : 0;
|
||||
|
||||
if (fl.m_Shadows)
|
||||
{
|
||||
RenderTexture shadowmap = light.GetBlurredShadowmap();
|
||||
if (shadowmap != null)
|
||||
{
|
||||
m_InjectLightingAndDensity.SetTexture(kernel, "_AreaLightShadowmap", shadowmap);
|
||||
m_InjectLightingAndDensity.SetFloat("_ESMExponentAreaLight", fl.m_ESMExponent);
|
||||
shadowedAreaLightIndex = j;
|
||||
}
|
||||
}
|
||||
|
||||
j++;
|
||||
}
|
||||
|
||||
m_AreaLightParamsCB.SetData(m_AreaLightParams);
|
||||
m_InjectLightingAndDensity.SetBuffer(kernel, "_AreaLights", m_AreaLightParamsCB);
|
||||
m_InjectLightingAndDensity.SetFloat("_ShadowedAreaLightIndex", shadowedAreaLightIndex);
|
||||
}
|
||||
|
||||
void SetUpFogEllipsoidBuffers(int kernel)
|
||||
{
|
||||
int count = 0;
|
||||
HashSet<FogEllipsoid> fogEllipsoids = LightManagerFogEllipsoids.Get();
|
||||
for (var x = fogEllipsoids.GetEnumerator(); x.MoveNext();) {
|
||||
var fe = x.Current;
|
||||
if (fe != null && fe.enabled && fe.gameObject.activeSelf)
|
||||
count++;
|
||||
}
|
||||
|
||||
m_InjectLightingAndDensity.SetFloat("_FogEllipsoidsCount", count);
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
if (m_FogEllipsoidParams == null || m_FogEllipsoidParams.Length != count)
|
||||
m_FogEllipsoidParams = new FogEllipsoidParams[count];
|
||||
|
||||
int j = 0;
|
||||
for (var x = fogEllipsoids.GetEnumerator(); x.MoveNext();)
|
||||
{
|
||||
var fe = x.Current;
|
||||
if (fe == null || !fe.enabled || !fe.gameObject.activeSelf)
|
||||
continue;
|
||||
|
||||
Transform t = fe.transform;
|
||||
|
||||
m_FogEllipsoidParams[j].pos = t.position;
|
||||
m_FogEllipsoidParams[j].radius = fe.m_Radius * fe.m_Radius;
|
||||
m_FogEllipsoidParams[j].axis = -t.up;
|
||||
m_FogEllipsoidParams[j].stretch = 1.0f/fe.m_Stretch - 1.0f;
|
||||
m_FogEllipsoidParams[j].density = fe.m_Density;
|
||||
m_FogEllipsoidParams[j].noiseAmount = fe.m_NoiseAmount;
|
||||
m_FogEllipsoidParams[j].noiseSpeed = fe.m_NoiseSpeed;
|
||||
m_FogEllipsoidParams[j].noiseScale = fe.m_NoiseScale;
|
||||
m_FogEllipsoidParams[j].feather = 1.0f - fe.m_Feather;
|
||||
m_FogEllipsoidParams[j].blend = fe.m_Blend == FogEllipsoid.Blend.Additive ? 0 : 1;
|
||||
j++;
|
||||
}
|
||||
|
||||
m_FogEllipsoidParamsCB.SetData(m_FogEllipsoidParams);
|
||||
m_InjectLightingAndDensity.SetBuffer(kernel, "_FogEllipsoids", m_FogEllipsoidParamsCB);
|
||||
}
|
||||
|
||||
FogLight GetDirectionalLight()
|
||||
{
|
||||
HashSet<FogLight> fogLights = LightManagerFogLights.Get();
|
||||
FogLight fogLight = null;
|
||||
|
||||
for (var x = fogLights.GetEnumerator(); x.MoveNext();)
|
||||
{
|
||||
var fl = x.Current;
|
||||
if (fl == null || fl.type != FogLight.Type.Directional || !fl.isOn)
|
||||
continue;
|
||||
|
||||
fogLight = fl;
|
||||
break;
|
||||
}
|
||||
|
||||
return fogLight;
|
||||
}
|
||||
|
||||
FogLight m_DirectionalLight;
|
||||
|
||||
void OnPreRender()
|
||||
{
|
||||
m_DirectionalLight = GetDirectionalLight();
|
||||
|
||||
if (m_DirectionalLight != null)
|
||||
m_DirectionalLight.UpdateDirectionalShadowmap();
|
||||
}
|
||||
|
||||
float[] m_dirLightColor;
|
||||
float[] m_dirLightDir;
|
||||
|
||||
void SetUpDirectionalLight(int kernel)
|
||||
{
|
||||
if (m_dirLightColor == null || m_dirLightColor.Length != 3)
|
||||
m_dirLightColor = new float[3];
|
||||
if (m_dirLightDir == null || m_dirLightDir.Length != 3)
|
||||
m_dirLightDir = new float[3];
|
||||
|
||||
if (m_DirectionalLight == null)
|
||||
{
|
||||
m_dirLightColor[0] = 0;
|
||||
m_dirLightColor[1] = 0;
|
||||
m_dirLightColor[2] = 0;
|
||||
m_InjectLightingAndDensity.SetFloats("_DirLightColor", m_dirLightColor);
|
||||
return;
|
||||
}
|
||||
|
||||
m_DirectionalLight.SetUpDirectionalShadowmapForSampling(m_DirectionalLight.m_Shadows, m_InjectLightingAndDensity, kernel);
|
||||
// TODO: if above fails, disable shadows
|
||||
|
||||
Light light = m_DirectionalLight.light;
|
||||
Vector4 color = light.color;
|
||||
color *= light.intensity * m_DirectionalLight.m_IntensityMult;
|
||||
m_dirLightColor[0] = color.x;
|
||||
m_dirLightColor[1] = color.y;
|
||||
m_dirLightColor[2] = color.z;
|
||||
m_InjectLightingAndDensity.SetFloats("_DirLightColor", m_dirLightColor);
|
||||
Vector3 dir = light.GetComponent<Transform>().forward;
|
||||
m_dirLightDir[0] = dir.x;
|
||||
m_dirLightDir[1] = dir.y;
|
||||
m_dirLightDir[2] = dir.z;
|
||||
m_InjectLightingAndDensity.SetFloats("_DirLightDir", m_dirLightDir);
|
||||
|
||||
}
|
||||
|
||||
float[] m_fogParams;
|
||||
float[] m_windDir;
|
||||
float[] m_ambientLight;
|
||||
|
||||
void SetUpForScatter(int kernel)
|
||||
{
|
||||
SanitizeInput();
|
||||
InitResources();
|
||||
SetFrustumRays();
|
||||
|
||||
// Compensate for more light and density being injected in per world space meter when near and far are closer.
|
||||
// TODO: Not quite correct yet.
|
||||
float depthCompensation = (farClip - nearClip) * 0.01f;
|
||||
m_InjectLightingAndDensity.SetFloat("_Density", m_GlobalDensityMult * 0.001f * depthCompensation);
|
||||
m_InjectLightingAndDensity.SetFloat("_Intensity", m_GlobalIntensityMult);
|
||||
m_InjectLightingAndDensity.SetFloat("_Anisotropy", m_Anisotropy);
|
||||
m_InjectLightingAndDensity.SetTexture(kernel, "_VolumeInject", m_VolumeInject);
|
||||
m_InjectLightingAndDensity.SetTexture(kernel, "_Shadowmap", m_BlurShadowmap ? m_ShadowmapBlurred : (m_Shadowmap != null ? m_Shadowmap : (Texture)Texture2D.whiteTexture));
|
||||
m_InjectLightingAndDensity.SetTexture(kernel, "_Noise", m_Noise);
|
||||
|
||||
if (m_fogParams == null || m_fogParams.Length != 4)
|
||||
m_fogParams = new float[4];
|
||||
if (m_windDir == null || m_windDir.Length != 3)
|
||||
m_windDir = new float[3];
|
||||
if (m_ambientLight == null || m_ambientLight.Length != 3)
|
||||
m_ambientLight = new float[3];
|
||||
m_fogParams[0] = m_ConstantFog;
|
||||
m_fogParams[1] = m_HeightFogExponent;
|
||||
m_fogParams[2] = m_HeightFogOffset;
|
||||
m_fogParams[3] = m_HeightFogAmount;
|
||||
|
||||
m_InjectLightingAndDensity.SetFloats("_FogParams", m_fogParams);
|
||||
m_InjectLightingAndDensity.SetFloat("_NoiseFogAmount", m_NoiseFogAmount);
|
||||
m_InjectLightingAndDensity.SetFloat("_NoiseFogScale", m_NoiseFogScale);
|
||||
m_InjectLightingAndDensity.SetFloat("_WindSpeed", m_Wind == null ? 0 : m_Wind.m_Speed);
|
||||
Vector3 windDir = m_Wind == null ? Vector3.forward : m_Wind.transform.forward;
|
||||
m_windDir[0] = windDir.x;
|
||||
m_windDir[1] = windDir.y;
|
||||
m_windDir[2] = windDir.z;
|
||||
m_InjectLightingAndDensity.SetFloats("_WindDir", m_windDir);
|
||||
m_InjectLightingAndDensity.SetFloat("_Time", Time.time);
|
||||
m_InjectLightingAndDensity.SetFloat("_NearOverFarClip", nearClip/farClip);
|
||||
Color ambient = m_AmbientLightColor * m_AmbientLightIntensity * 0.1f;
|
||||
m_ambientLight[0] = ambient.r;
|
||||
m_ambientLight[1] = ambient.g;
|
||||
m_ambientLight[2] = ambient.b;
|
||||
m_InjectLightingAndDensity.SetFloats("_AmbientLight", m_ambientLight);
|
||||
|
||||
SetUpPointLightBuffers(kernel);
|
||||
SetUpTubeLightBuffers(kernel);
|
||||
SetUpAreaLightBuffers(kernel);
|
||||
SetUpFogEllipsoidBuffers(kernel);
|
||||
SetUpDirectionalLight(kernel);
|
||||
}
|
||||
|
||||
void Scatter()
|
||||
{
|
||||
// Inject lighting and density
|
||||
int kernel = 0;
|
||||
|
||||
SetUpForScatter(kernel);
|
||||
|
||||
m_InjectLightingAndDensity.Dispatch(kernel, m_VolumeResolution.x/m_InjectNumThreads.x, m_VolumeResolution.y/m_InjectNumThreads.y, m_VolumeResolution.z/m_InjectNumThreads.z);
|
||||
|
||||
// Solve scattering
|
||||
m_Scatter.SetTexture(0, "_VolumeInject", m_VolumeInject);
|
||||
m_Scatter.SetTexture(0, "_VolumeScatter", m_VolumeScatter);
|
||||
m_Scatter.Dispatch(0, m_VolumeResolution.x/m_ScatterNumThreads.x, m_VolumeResolution.y/m_ScatterNumThreads.y, 1);
|
||||
|
||||
ReleaseTempResources();
|
||||
}
|
||||
|
||||
void DebugDisplay(RenderTexture src, RenderTexture dest)
|
||||
{
|
||||
InitMaterial(ref m_DebugMaterial, m_DebugShader);
|
||||
|
||||
m_DebugMaterial.SetTexture("_VolumeInject", m_VolumeInject);
|
||||
m_DebugMaterial.SetTexture("_VolumeScatter", m_VolumeScatter);
|
||||
m_DebugMaterial.SetTexture("_Shadowmap", m_Shadowmap);
|
||||
m_DebugMaterial.SetTexture("_ShadowmapBlurred", m_ShadowmapBlurred);
|
||||
m_DebugMaterial.SetFloat("_Z", m_Z);
|
||||
|
||||
m_DebugMaterial.SetTexture("_MainTex", src);
|
||||
|
||||
Graphics.Blit(src, dest, m_DebugMaterial);
|
||||
}
|
||||
|
||||
void SetUpGlobalFogSamplingUniforms(int width, int height)
|
||||
{
|
||||
Shader.SetGlobalTexture("_VolumeScatter", m_VolumeScatter);
|
||||
Shader.SetGlobalVector("_Screen_TexelSize", new Vector4(1.0f / width, 1.0f / height, width, height));
|
||||
Shader.SetGlobalVector("_VolumeScatter_TexelSize", new Vector4(1.0f / m_VolumeResolution.x, 1.0f / m_VolumeResolution.y, 1.0f / m_VolumeResolution.z, 0));
|
||||
Shader.SetGlobalFloat("_CameraFarOverMaxFar", cam.farClipPlane / farClip);
|
||||
Shader.SetGlobalFloat("_NearOverFarClip", nearClip / farClip);
|
||||
}
|
||||
|
||||
[ImageEffectOpaque]
|
||||
void OnRenderImage(RenderTexture src, RenderTexture dest)
|
||||
{
|
||||
if(m_Debug)
|
||||
{
|
||||
DebugDisplay(src, dest);
|
||||
return;
|
||||
}
|
||||
|
||||
Scatter();
|
||||
|
||||
InitMaterial(ref m_ApplyToOpaqueMaterial, m_ApplyToOpaqueShader);
|
||||
|
||||
// TODO: This shouldn't be needed. Is it because the shader doesn't have the Property block?
|
||||
m_ApplyToOpaqueMaterial.SetTexture("_MainTex", src);
|
||||
|
||||
SetUpGlobalFogSamplingUniforms(src.width, src.height);
|
||||
|
||||
Graphics.Blit(src, dest, m_ApplyToOpaqueMaterial);
|
||||
|
||||
VolumetricFogInForward(true);
|
||||
}
|
||||
|
||||
void OnPostRender()
|
||||
{
|
||||
VolumetricFogInForward(false);
|
||||
}
|
||||
|
||||
void VolumetricFogInForward(bool enable)
|
||||
{
|
||||
if (enable)
|
||||
Shader.EnableKeyword("VOLUMETRIC_FOG");
|
||||
else
|
||||
Shader.DisableKeyword("VOLUMETRIC_FOG");
|
||||
}
|
||||
|
||||
Vector3 ViewportToLocalPoint(Camera c, Transform t, Vector3 p)
|
||||
{
|
||||
// TODO: viewporttoworldpoint inverts the clip-to-world matrix every time without caching it.
|
||||
return t.InverseTransformPoint(c.ViewportToWorldPoint(p));
|
||||
}
|
||||
|
||||
static readonly Vector2[] frustumUVs =
|
||||
new Vector2[] {new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1), new Vector2(0, 1)};
|
||||
static float[] frustumRays = new float[16];
|
||||
|
||||
void SetFrustumRays()
|
||||
{
|
||||
float far = farClip;
|
||||
Vector3 cameraPos = cam.transform.position;
|
||||
Vector2[] uvs = frustumUVs;
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
Vector3 ray = cam.ViewportToWorldPoint(new Vector3(uvs[i].x, uvs[i].y, far)) - cameraPos;
|
||||
frustumRays[i*4+0] = ray.x;
|
||||
frustumRays[i*4+1] = ray.y;
|
||||
frustumRays[i*4+2] = ray.z;
|
||||
frustumRays[i*4+3] = 0;
|
||||
}
|
||||
|
||||
m_InjectLightingAndDensity.SetVector("_CameraPos", cameraPos);
|
||||
m_InjectLightingAndDensity.SetFloats("_FrustumRays", frustumRays);
|
||||
}
|
||||
|
||||
void InitVolume(ref RenderTexture volume)
|
||||
{
|
||||
if(volume)
|
||||
return;
|
||||
|
||||
volume = new RenderTexture (m_VolumeResolution.x, m_VolumeResolution.y, 0, RenderTextureFormat.ARGBHalf);
|
||||
volume.volumeDepth = m_VolumeResolution.z;
|
||||
volume.dimension = UnityEngine.Rendering.TextureDimension.Tex3D;
|
||||
volume.enableRandomWrite = true;
|
||||
volume.Create();
|
||||
}
|
||||
|
||||
void CreateBuffer(ref ComputeBuffer buffer, int count, int stride)
|
||||
{
|
||||
if (buffer != null && buffer.count == count)
|
||||
return;
|
||||
|
||||
if(buffer != null)
|
||||
{
|
||||
buffer.Release();
|
||||
buffer = null;
|
||||
}
|
||||
|
||||
if (count <= 0)
|
||||
return;
|
||||
|
||||
buffer = new ComputeBuffer(count, stride);
|
||||
}
|
||||
|
||||
void InitResources ()
|
||||
{
|
||||
// Shadowmap
|
||||
m_Shadowmap = RenderTexture.GetTemporary(m_ShadowmapRes, m_ShadowmapRes, 24, RenderTextureFormat.RFloat);
|
||||
m_Shadowmap.filterMode = FilterMode.Bilinear;
|
||||
m_Shadowmap.wrapMode = TextureWrapMode.Clamp;
|
||||
|
||||
// Volume
|
||||
InitVolume(ref m_VolumeInject);
|
||||
InitVolume(ref m_VolumeScatter);
|
||||
|
||||
|
||||
// Compute buffers
|
||||
int pointLightCount = 0, tubeLightCount = 0, areaLightCount = 0;
|
||||
HashSet<FogLight> fogLights = LightManagerFogLights.Get();
|
||||
for (var x = fogLights.GetEnumerator(); x.MoveNext();)
|
||||
{
|
||||
var fl = x.Current;
|
||||
if (fl == null)
|
||||
continue;
|
||||
|
||||
bool isOn = fl.isOn;
|
||||
|
||||
switch(fl.type)
|
||||
{
|
||||
case FogLight.Type.Point: if (isOn) pointLightCount++; break;
|
||||
case FogLight.Type.Tube: if (isOn) tubeLightCount++; break;
|
||||
case FogLight.Type.Area: if (isOn) areaLightCount++; break;
|
||||
}
|
||||
}
|
||||
|
||||
// PointLightParams {float3 float float3 float} -> 32 bytes
|
||||
CreateBuffer(ref m_PointLightParamsCB, pointLightCount, 32);
|
||||
|
||||
// TubeLightParams {float3 float float3 float float3 float} -> 48 bytes
|
||||
CreateBuffer(ref m_TubeLightParamsCB, tubeLightCount, 48);
|
||||
|
||||
// TubeLightShadowPlaneParams {float4 float4 float float float float} -> 48 bytes
|
||||
CreateBuffer(ref m_TubeLightShadowPlaneParamsCB, tubeLightCount, 48);
|
||||
|
||||
// TubeLightParams {float4x4 float4 float3 float} -> 96 bytes
|
||||
CreateBuffer(ref m_AreaLightParamsCB, areaLightCount, 96);
|
||||
|
||||
// FogEllipsoidParams {float3 float float3 9xfloat} -> 64 bytes
|
||||
HashSet<FogEllipsoid> fogEllipsoids = LightManagerFogEllipsoids.Get();
|
||||
CreateBuffer(ref m_FogEllipsoidParamsCB, fogEllipsoids == null ? 0 : fogEllipsoids.Count, 64);
|
||||
}
|
||||
|
||||
void ReleaseTemporary(ref RenderTexture rt)
|
||||
{
|
||||
if (rt == null)
|
||||
return;
|
||||
|
||||
RenderTexture.ReleaseTemporary(rt);
|
||||
rt = null;
|
||||
}
|
||||
|
||||
void ReleaseTempResources()
|
||||
{
|
||||
ReleaseTemporary(ref m_Shadowmap);
|
||||
ReleaseTemporary(ref m_ShadowmapBlurred);
|
||||
}
|
||||
|
||||
void InitMaterial(ref Material material, Shader shader)
|
||||
{
|
||||
if (material)
|
||||
return;
|
||||
|
||||
if (!shader)
|
||||
{
|
||||
Debug.LogError("Missing shader");
|
||||
return;
|
||||
}
|
||||
|
||||
material = new Material(shader);
|
||||
material.hideFlags = HideFlags.HideAndDontSave;
|
||||
}
|
||||
|
||||
void OnDrawGizmosSelected()
|
||||
{
|
||||
Gizmos.color = Color.yellow;
|
||||
Gizmos.matrix = transform.localToWorldMatrix;
|
||||
Gizmos.DrawFrustum(Vector3.zero, cam.fieldOfView, farClip, nearClip, cam.aspect);
|
||||
}
|
||||
}
|
23
Assets/VolumetricFog/Scripts/VolumetricFog.cs.meta
Normal file
23
Assets/VolumetricFog/Scripts/VolumetricFog.cs.meta
Normal file
@ -0,0 +1,23 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f35c02a2c6230584391703bf32006791
|
||||
timeCreated: 1432253353
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences:
|
||||
- m_DebugShader: {fileID: 4800000, guid: 91e29ad407521e447a7254f5c1ea9b54, type: 3}
|
||||
- m_ShadowmapShader: {fileID: 4800000, guid: 2c4cd42b134f7864fa579350e9cf6896, type: 3}
|
||||
- m_InjectLightingAndDensity: {fileID: 7200000, guid: 55812fd61bd54104aa23612fc28bfeb8,
|
||||
type: 3}
|
||||
- m_Scatter: {fileID: 7200000, guid: 2a7c01c2354d03a4e9c31096bf130b6a, type: 3}
|
||||
- m_ApplyToOpaqueShader: {fileID: 4800000, guid: 6f73df8e11615074dbf62a3a384af521,
|
||||
type: 3}
|
||||
- m_BlurShadowmapShader: {fileID: 4800000, guid: 701192b62a7678549918bc87434699fe,
|
||||
type: 3}
|
||||
- m_Noise: {fileID: 2800000, guid: 35eb47181d630134c97488476efbda59, type: 3}
|
||||
- m_Sun: {instanceID: 0}
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
9
Assets/VolumetricFog/Shaders.meta
Normal file
9
Assets/VolumetricFog/Shaders.meta
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f9f2001f237efb348b16ef606855bab7
|
||||
folderAsset: yes
|
||||
timeCreated: 1477749236
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
48
Assets/VolumetricFog/Shaders/ApplyToOpaque.shader
Normal file
48
Assets/VolumetricFog/Shaders/ApplyToOpaque.shader
Normal file
@ -0,0 +1,48 @@
|
||||
Shader "Hidden/ApplyToOpaque" {
|
||||
SubShader {
|
||||
Pass {
|
||||
ZTest Always Cull Off ZWrite Off
|
||||
Blend Off
|
||||
|
||||
CGPROGRAM
|
||||
#pragma target 3.0
|
||||
#include "UnityCG.cginc"
|
||||
#include "VolumetricFog.cginc"
|
||||
#pragma vertex vert
|
||||
#pragma fragment frag
|
||||
|
||||
sampler2D _CameraDepthTexture;
|
||||
sampler2D _MainTex;
|
||||
|
||||
struct v2f
|
||||
{
|
||||
float4 pos : SV_POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
v2f vert (appdata_img v)
|
||||
{
|
||||
v2f o;
|
||||
o.pos = v.vertex;
|
||||
o.pos.xy = o.pos.xy * 2 - 1;
|
||||
o.uv = v.texcoord.xy;
|
||||
|
||||
#if UNITY_UV_STARTS_AT_TOP
|
||||
if (_ProjectionParams.x < 0)
|
||||
o.uv.y = 1-o.uv.y;
|
||||
#endif
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
half4 frag (v2f i) : SV_Target
|
||||
{
|
||||
half linear01Depth = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv));
|
||||
half4 fog = Fog(linear01Depth, i.uv);
|
||||
return tex2D(_MainTex, i.uv) * fog.a + fog;
|
||||
}
|
||||
|
||||
ENDCG
|
||||
}
|
||||
}
|
||||
}
|
9
Assets/VolumetricFog/Shaders/ApplyToOpaque.shader.meta
Normal file
9
Assets/VolumetricFog/Shaders/ApplyToOpaque.shader.meta
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6f73df8e11615074dbf62a3a384af521
|
||||
timeCreated: 1432216767
|
||||
licenseType: Pro
|
||||
ShaderImporter:
|
||||
defaultTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
240
Assets/VolumetricFog/Shaders/BlurShadowmap.shader
Normal file
240
Assets/VolumetricFog/Shaders/BlurShadowmap.shader
Normal file
@ -0,0 +1,240 @@
|
||||
|
||||
Shader "Hidden/BlurShadowmap" {
|
||||
Properties
|
||||
{
|
||||
_MainTex ("Base (RGB)", 2D) = "white" {}
|
||||
_Bloom ("Bloom (RGB)", 2D) = "black" {}
|
||||
}
|
||||
|
||||
CGINCLUDE
|
||||
#include "UnityCG.cginc"
|
||||
|
||||
half4 _TexelSize;
|
||||
|
||||
struct v2f_tap
|
||||
{
|
||||
float4 pos : SV_POSITION;
|
||||
half2 uv20 : TEXCOORD0;
|
||||
half2 uv21 : TEXCOORD1;
|
||||
half2 uv22 : TEXCOORD2;
|
||||
half2 uv23 : TEXCOORD3;
|
||||
};
|
||||
|
||||
v2f_tap vert4Tap ( appdata_img v )
|
||||
{
|
||||
v2f_tap o;
|
||||
o.pos = v.vertex;
|
||||
|
||||
o.uv20 = v.texcoord + _TexelSize.xy;
|
||||
o.uv21 = v.texcoord + _TexelSize.xy * half2(-0.5, -0.5);
|
||||
o.uv22 = v.texcoord + _TexelSize.xy * half2( 0.5, -0.5);
|
||||
o.uv23 = v.texcoord + _TexelSize.xy * half2(-0.5, 0.5);
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
// TODO: consolidate with the above, but make sure both area and dir shadows work
|
||||
v2f_tap vert4TapDir ( appdata_img v )
|
||||
{
|
||||
v2f_tap o;
|
||||
o.pos = UnityObjectToClipPos(v.vertex);
|
||||
|
||||
o.uv20 = v.texcoord + _TexelSize.xy;
|
||||
o.uv21 = v.texcoord + _TexelSize.xy * half2(-0.5, -0.5);
|
||||
o.uv22 = v.texcoord + _TexelSize.xy * half2( 0.5, -0.5);
|
||||
o.uv23 = v.texcoord + _TexelSize.xy * half2(-0.5, 0.5);
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
float4 _ZParams;
|
||||
float _ESMExponent;
|
||||
Texture2D _Shadowmap;
|
||||
SamplerComparisonState sampler_Shadowmap;
|
||||
|
||||
// To get a sampler, which doesn't do comparison
|
||||
Texture2D _ShadowmapDummy;
|
||||
SamplerState sampler_ShadowmapDummy;
|
||||
|
||||
#define VSM 1
|
||||
|
||||
float4 fragDownsampleFromShadowmapFormat ( v2f_tap i ) : SV_Target
|
||||
{
|
||||
float4 z;
|
||||
z.r = _Shadowmap.Sample(sampler_ShadowmapDummy, i.uv20).r;
|
||||
z.g = _Shadowmap.Sample(sampler_ShadowmapDummy, i.uv21).r;
|
||||
z.b = _Shadowmap.Sample(sampler_ShadowmapDummy, i.uv22).r;
|
||||
z.a = _Shadowmap.Sample(sampler_ShadowmapDummy, i.uv23).r;
|
||||
|
||||
// The texture contains just 0. But we need to sample it somewhere for Unity to initialize the corresponding sampler.
|
||||
z.r += _ShadowmapDummy.Sample(sampler_ShadowmapDummy, 0).a;
|
||||
|
||||
// Transform to linear z, 0 at near, 1 at far
|
||||
z = z * 2 - 1;
|
||||
z = _ZParams.x * (z + 1.0) / (z + _ZParams.y);
|
||||
|
||||
#if VSM
|
||||
// TODO: this is wrong. We can't average/blur z values before converting to VSM.
|
||||
// This doesn't affect m, but affects m * m, so I should swap those two lines.
|
||||
float m = dot(z, 0.25);
|
||||
return float4(m, m * m, 0, 0);
|
||||
#else
|
||||
z = exp(_ESMExponent * z);
|
||||
return dot(z, 0.25);
|
||||
#endif
|
||||
}
|
||||
|
||||
sampler2D _DirShadowmap;
|
||||
|
||||
float4 fragDownsampleFromShadowmapFormatDir ( v2f_tap i ) : SV_Target
|
||||
{
|
||||
float4 z;
|
||||
z.r = tex2D (_DirShadowmap, i.uv20).r;
|
||||
z.g = tex2D (_DirShadowmap, i.uv21).r;
|
||||
z.b = tex2D (_DirShadowmap, i.uv22).r;
|
||||
z.a = tex2D (_DirShadowmap, i.uv23).r;
|
||||
|
||||
return z.r;
|
||||
|
||||
// Transform to linear z, 0 at near, 1 at far
|
||||
// z = z * 2 - 1;
|
||||
// z = _ZParams.x * (z + 1.0) / (z + _ZParams.y);
|
||||
|
||||
#if 1
|
||||
// float m = dot(z, 0.25);
|
||||
// return float4(m, m * m, 0, 0);
|
||||
float4 z2 = z * z;
|
||||
return float4(dot(z, 0.25), dot(z2, 0.25), 0, 0);
|
||||
#else
|
||||
//z = exp(_ESMExponent * z);
|
||||
z = exp(40.0 * z);
|
||||
return dot(z, 0.25);
|
||||
#endif
|
||||
}
|
||||
|
||||
sampler2D _MainTex;
|
||||
|
||||
float4 fragDownsample ( v2f_tap i ) : SV_Target
|
||||
{
|
||||
float4 color = tex2D (_MainTex, i.uv20);
|
||||
color += tex2D (_MainTex, i.uv21);
|
||||
color += tex2D (_MainTex, i.uv22);
|
||||
color += tex2D (_MainTex, i.uv23);
|
||||
return color * 0.25;
|
||||
}
|
||||
|
||||
struct v2f
|
||||
{
|
||||
float4 pos : SV_POSITION;
|
||||
half4 uv : TEXCOORD0;
|
||||
half2 offs : TEXCOORD1;
|
||||
};
|
||||
|
||||
float _BlurSize;
|
||||
|
||||
v2f vertBlurHorizontal (appdata_img v)
|
||||
{
|
||||
v2f o;
|
||||
o.pos = v.vertex;
|
||||
|
||||
o.uv = half4(v.texcoord.xy,1,1);
|
||||
o.offs = _TexelSize.xy * half2(1.0, 0.0) * _BlurSize;
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
v2f vertBlurVertical (appdata_img v)
|
||||
{
|
||||
v2f o;
|
||||
o.pos = v.vertex;
|
||||
|
||||
o.uv = half4(v.texcoord.xy, 1, 1);
|
||||
o.offs = _TexelSize.xy * half2(0.0, 1.0) * _BlurSize;
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
float4 fragBlur8 (v2f i) : SV_Target
|
||||
{
|
||||
half2 coords = i.uv.xy - i.offs * 5.0;
|
||||
|
||||
float4 color = 0;
|
||||
for(int k = 0; k < 11; k++)
|
||||
{
|
||||
color += tex2D(_MainTex, coords);
|
||||
coords += i.offs;
|
||||
}
|
||||
return color/11.0;
|
||||
}
|
||||
|
||||
ENDCG
|
||||
|
||||
SubShader {
|
||||
ZTest Off Cull Off ZWrite Off Blend Off
|
||||
|
||||
// 0
|
||||
Pass
|
||||
{
|
||||
CGPROGRAM
|
||||
#pragma vertex vert4Tap
|
||||
#pragma fragment fragDownsampleFromShadowmapFormat
|
||||
ENDCG
|
||||
}
|
||||
|
||||
// 1
|
||||
Pass
|
||||
{
|
||||
CGPROGRAM
|
||||
#pragma vertex vert4Tap
|
||||
#pragma fragment fragDownsample
|
||||
ENDCG
|
||||
}
|
||||
|
||||
// 2
|
||||
Pass {
|
||||
ZTest Always
|
||||
Cull Off
|
||||
|
||||
CGPROGRAM
|
||||
|
||||
#pragma vertex vertBlurVertical
|
||||
#pragma fragment fragBlur8
|
||||
|
||||
ENDCG
|
||||
}
|
||||
|
||||
// 3
|
||||
Pass {
|
||||
ZTest Always
|
||||
Cull Off
|
||||
|
||||
CGPROGRAM
|
||||
|
||||
#pragma vertex vertBlurHorizontal
|
||||
#pragma fragment fragBlur8
|
||||
|
||||
ENDCG
|
||||
}
|
||||
|
||||
// 4
|
||||
Pass
|
||||
{
|
||||
CGPROGRAM
|
||||
#pragma vertex vert4TapDir
|
||||
#pragma fragment fragDownsampleFromShadowmapFormatDir
|
||||
ENDCG
|
||||
}
|
||||
|
||||
// 5
|
||||
Pass
|
||||
{
|
||||
CGPROGRAM
|
||||
#pragma vertex vert4TapDir
|
||||
#pragma fragment fragDownsample
|
||||
ENDCG
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
FallBack Off
|
||||
}
|
9
Assets/VolumetricFog/Shaders/BlurShadowmap.shader.meta
Normal file
9
Assets/VolumetricFog/Shaders/BlurShadowmap.shader.meta
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 701192b62a7678549918bc87434699fe
|
||||
timeCreated: 1432227463
|
||||
licenseType: Pro
|
||||
ShaderImporter:
|
||||
defaultTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
43
Assets/VolumetricFog/Shaders/CopyShadowParams.shader
Normal file
43
Assets/VolumetricFog/Shaders/CopyShadowParams.shader
Normal file
@ -0,0 +1,43 @@
|
||||
Shader "Hidden/CopyShadowParams"
|
||||
{
|
||||
SubShader
|
||||
{
|
||||
Pass
|
||||
{
|
||||
CGPROGRAM
|
||||
#pragma target 5.0
|
||||
#pragma only_renderers d3d11
|
||||
#pragma vertex vert
|
||||
#pragma fragment frag
|
||||
#include "UnityCG.cginc"
|
||||
|
||||
struct ShadowParams
|
||||
{
|
||||
float4x4 worldToShadow[4];
|
||||
float4 shadowSplitSpheres[4];
|
||||
float4 shadowSplitSqRadii;
|
||||
};
|
||||
|
||||
// Hmm, we can't be sure u2 doesn't conflict with other effects.
|
||||
RWStructuredBuffer<ShadowParams> _ShadowParams : register(u2);
|
||||
|
||||
float4 vert () : SV_POSITION
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
_ShadowParams[0].worldToShadow[i] = unity_WorldToShadow[i];
|
||||
_ShadowParams[0].shadowSplitSpheres[i] = unity_ShadowSplitSpheres[i];
|
||||
}
|
||||
_ShadowParams[0].shadowSplitSqRadii = unity_ShadowSplitSqRadii;
|
||||
|
||||
return float4(0, 0, 0, 1);
|
||||
}
|
||||
|
||||
fixed4 frag () : SV_Target
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
ENDCG
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user