浏览代码

first pass at shadows with FPTL

/main
vlad-andreev 8 年前
当前提交
43fe87ad
共有 3 个文件被更改,包括 277 次插入4 次删除
  1. 131
      Assets/ScriptableRenderLoop/fptl/FptlLighting.cs
  2. 133
      Assets/ScriptableRenderLoop/fptl/Internal-DeferredShading.shader
  3. 17
      Assets/ScriptableRenderLoop/fptl/LightDefinitions.cs

131
Assets/ScriptableRenderLoop/fptl/FptlLighting.cs


using UnityEngine;
using UnityEngine.Rendering;
using System;
using UnityEditor;
namespace UnityEngine.ScriptableRenderLoop

AssetDatabase.CreateAsset(instance, "Assets/renderloopfptl.asset");
//AssetDatabase.CreateAsset(instance, "Assets/ScriptableRenderLoop/fptl/renderloopfptl.asset");
}
[SerializeField]
ShadowSettings m_ShadowSettings = ShadowSettings.Default;
ShadowRenderPass m_ShadowPass;
public Shader m_DeferredShader;
public Shader m_DeferredReflectionShader;

public const int gMaxNumLights = 1024;
public const float gFltMax = 3.402823466e+38F;
const int MAX_LIGHTS = 10;
const int MAX_SHADOWMAP_PER_LIGHTS = 6;
const int MAX_DIRECTIONAL_SPLIT = 4;
// Directional lights become spotlights at a far distance. This is the distance we pull back to set the spotlight origin.
const float DIRECTIONAL_LIGHT_PULLBACK_DISTANCE = 10000.0f;
[NonSerialized]
private int m_nWarnedTooManyLights = 0;
private TextureCache2D m_cookieTexArray;
private TextureCacheCubemap m_cubeCookieTexArray;

m_DeferredMaterial.SetTexture("_spotCookieTextures", m_cookieTexArray.GetTexCache());
m_DeferredMaterial.SetTexture("_pointCookieTextures", m_cubeCookieTexArray.GetTexCache());
m_DeferredReflectionMaterial.SetTexture("_reflCubeTextures", m_cubeReflTexArray.GetTexCache());
m_ShadowPass = new ShadowRenderPass(m_ShadowSettings);
}
void OnDisable()

cmd.SetComputeFloatParams(shadercs, name, data);
}
//---------------------------------------------------------------------------------------------------------------------------------------------------
void UpdateShadowConstants(ActiveLight[] activeLights, ref ShadowOutput shadow)
{
int nNumLightsIncludingTooMany = 0;
int g_nNumLights = 0;
Vector4[] g_vLightShadowIndex_vLightParams = new Vector4[MAX_LIGHTS];
Vector4[] g_vLightFalloffParams = new Vector4[MAX_LIGHTS];
Matrix4x4[] g_matWorldToShadow = new Matrix4x4[MAX_LIGHTS * MAX_SHADOWMAP_PER_LIGHTS];
Vector4[] g_vDirShadowSplitSpheres = new Vector4[MAX_DIRECTIONAL_SPLIT];
for (int nLight = 0; nLight < activeLights.Length; nLight++)
{
nNumLightsIncludingTooMany++;
if (nNumLightsIncludingTooMany > MAX_LIGHTS)
continue;
ActiveLight light = activeLights[nLight];
LightType lightType = light.lightType;
Vector3 position = light.light.transform.position;
Vector3 lightDir = light.light.transform.forward.normalized;
// Setup shadow data arrays
bool hasShadows = shadow.GetShadowSliceCountLightIndex(nLight) != 0;
if (lightType == LightType.Directional)
{
g_vLightShadowIndex_vLightParams[g_nNumLights] = new Vector4(0, 0, 1, 1);
g_vLightFalloffParams[g_nNumLights] = new Vector4(0.0f, 0.0f, float.MaxValue, (float)lightType);
if (hasShadows)
{
for (int s = 0; s < MAX_DIRECTIONAL_SPLIT; ++s)
{
g_vDirShadowSplitSpheres[s] = shadow.directionalShadowSplitSphereSqr[s];
}
}
}
else if (lightType == LightType.Point)
{
g_vLightShadowIndex_vLightParams[g_nNumLights] = new Vector4(0, 0, 1, 1);
g_vLightFalloffParams[g_nNumLights] = new Vector4(1.0f, 0.0f, light.range * light.range, (float)lightType);
}
else if (lightType == LightType.Spot)
{
g_vLightShadowIndex_vLightParams[g_nNumLights] = new Vector4(0, 0, 1, 1);
g_vLightFalloffParams[g_nNumLights] = new Vector4(1.0f, 0.0f, light.range * light.range, (float)lightType);
}
if (hasShadows)
{
// Enable shadows
g_vLightShadowIndex_vLightParams[g_nNumLights].x = 1;
for (int s = 0; s < shadow.GetShadowSliceCountLightIndex(nLight); ++s)
{
int shadowSliceIndex = shadow.GetShadowSliceIndex(nLight, s);
g_matWorldToShadow[g_nNumLights * MAX_SHADOWMAP_PER_LIGHTS + s] = shadow.shadowSlices[shadowSliceIndex].shadowTransform.transpose;
}
}
g_nNumLights++;
}
// Warn if too many lights found
if (nNumLightsIncludingTooMany > MAX_LIGHTS)
{
if (nNumLightsIncludingTooMany > m_nWarnedTooManyLights)
{
Debug.LogError("ERROR! Found " + nNumLightsIncludingTooMany + " runtime lights! Valve renderer supports up to " + MAX_LIGHTS +
" active runtime lights at a time!\nDisabling " + (nNumLightsIncludingTooMany - MAX_LIGHTS) + " runtime light" +
((nNumLightsIncludingTooMany - MAX_LIGHTS) > 1 ? "s" : "") + "!\n");
}
m_nWarnedTooManyLights = nNumLightsIncludingTooMany;
}
else
{
if (m_nWarnedTooManyLights > 0)
{
m_nWarnedTooManyLights = 0;
Debug.Log("SUCCESS! Found " + nNumLightsIncludingTooMany + " runtime lights which is within the supported number of lights, " + MAX_LIGHTS + ".\n\n");
}
}
// Send constants to shaders
Shader.SetGlobalMatrixArray("g_matWorldToShadow", g_matWorldToShadow);
Shader.SetGlobalVectorArray("g_vDirShadowSplitSpheres", g_vDirShadowSplitSpheres);
// PCF 3x3 Shadows
float flTexelEpsilonX = 1.0f / m_ShadowSettings.shadowAtlasWidth;
float flTexelEpsilonY = 1.0f / m_ShadowSettings.shadowAtlasHeight;
Vector4 g_vShadow3x3PCFTerms0 = new Vector4(20.0f / 267.0f, 33.0f / 267.0f, 55.0f / 267.0f, 0.0f);
Vector4 g_vShadow3x3PCFTerms1 = new Vector4(flTexelEpsilonX, flTexelEpsilonY, -flTexelEpsilonX, -flTexelEpsilonY);
Vector4 g_vShadow3x3PCFTerms2 = new Vector4(flTexelEpsilonX, flTexelEpsilonY, 0.0f, 0.0f);
Vector4 g_vShadow3x3PCFTerms3 = new Vector4(-flTexelEpsilonX, -flTexelEpsilonY, 0.0f, 0.0f);
Shader.SetGlobalVector("g_vShadow3x3PCFTerms0", g_vShadow3x3PCFTerms0);
Shader.SetGlobalVector("g_vShadow3x3PCFTerms1", g_vShadow3x3PCFTerms1);
Shader.SetGlobalVector("g_vShadow3x3PCFTerms2", g_vShadow3x3PCFTerms2);
Shader.SetGlobalVector("g_vShadow3x3PCFTerms3", g_vShadow3x3PCFTerms3);
}
int GenerateSourceLightBuffers(Camera camera, CullResults inputs)
{
ReflectionProbe[] probes = Object.FindObjectsOfType<ReflectionProbe>();

Matrix4x4 worldToView = camera.worldToCameraMatrix;
int i = 0;
uint shadowLightIndex = 0;
foreach (var cl in inputs.culledLights)
{
float range = cl.range;

lightData[i].vCol = new Vec3(cl.finalColor.r, cl.finalColor.g, cl.finalColor.b);
lightData[i].iSliceIndex = 0;
lightData[i].uLightModel = (uint)LightDefinitions.DIRECT_LIGHT;
lightData[i].uShadowLightIndex = shadowLightIndex;
shadowLightIndex++;
bool bHasCookie = cl.light.cookie != null;

if (!CullResults.GetCullingParameters(camera, out cullingParams))
continue;
m_ShadowPass.UpdateCullingParameters(ref cullingParams);
if (CullResults.Cull(camera, renderLoop, out cullResults))
ExecuteRenderLoop(camera, cullResults, renderLoop);
}

// do anything we need to do upon a new frame.
NewFrame();
ShadowOutput shadows;
m_ShadowPass.Render(loop, cullResults, out shadows);
UpdateShadowConstants(cullResults.culledLights, ref shadows);
RenderGBuffer(cullResults, camera, loop);
//@TODO: render forward-only objects into depth buffer

133
Assets/ScriptableRenderLoop/fptl/Internal-DeferredShading.shader


StructuredBuffer<SFiniteLightData> g_vLightData;
//---------------------------------------------------------------------------------------------------------------------------------------------------------
// TODO: clean up.. -va
#define MAX_SHADOW_LIGHTS 10
#define MAX_SHADOWMAP_PER_LIGHT 6
#define MAX_DIRECTIONAL_SPLIT 4
#define CUBEMAPFACE_POSITIVE_X 0
#define CUBEMAPFACE_NEGATIVE_X 1
#define CUBEMAPFACE_POSITIVE_Y 2
#define CUBEMAPFACE_NEGATIVE_Y 3
#define CUBEMAPFACE_POSITIVE_Z 4
#define CUBEMAPFACE_NEGATIVE_Z 5
CBUFFER_START(ShadowLightData)
float4 g_vShadow3x3PCFTerms0;
float4 g_vShadow3x3PCFTerms1;
float4 g_vShadow3x3PCFTerms2;
float4 g_vShadow3x3PCFTerms3;
float4 g_vDirShadowSplitSpheres[MAX_DIRECTIONAL_SPLIT];
float4x4 g_matWorldToShadow[MAX_SHADOW_LIGHTS * MAX_SHADOWMAP_PER_LIGHT];
CBUFFER_END
//---------------------------------------------------------------------------------------------------------------------------------------------------------
float GetLinearDepth(float3 vP)
{
Vec3 var = 1.0;

float3 ExecuteLightList(uint2 pixCoord, const uint offs);
float3 OverlayHeatMap(uint uNumLights, float3 c);
#define VALVE_DECLARE_SHADOWMAP( tex ) Texture2D tex; SamplerComparisonState sampler##tex
#define VALVE_SAMPLE_SHADOW( tex, coord ) tex.SampleCmpLevelZero( sampler##tex, (coord).xy, (coord).z )
VALVE_DECLARE_SHADOWMAP(g_tShadowBuffer);
float ComputeShadow_PCF_3x3_Gaussian(float3 vPositionWs, float4x4 matWorldToShadow)
{
float4 vPositionTextureSpace = mul(float4(vPositionWs.xyz, 1.0), matWorldToShadow);
vPositionTextureSpace.xyz /= vPositionTextureSpace.w;
float2 shadowMapCenter = vPositionTextureSpace.xy;
if ((shadowMapCenter.x < 0.0f) || (shadowMapCenter.x > 1.0f) || (shadowMapCenter.y < 0.0f) || (shadowMapCenter.y > 1.0f))
return 1.0f;
float objDepth = saturate(1.001f - vPositionTextureSpace.z);
float4 v20Taps;
v20Taps.x = VALVE_SAMPLE_SHADOW(g_tShadowBuffer, float3(shadowMapCenter.xy + g_vShadow3x3PCFTerms1.xy, objDepth)).x; // 1 1
v20Taps.y = VALVE_SAMPLE_SHADOW(g_tShadowBuffer, float3(shadowMapCenter.xy + g_vShadow3x3PCFTerms1.zy, objDepth)).x; // -1 1
v20Taps.z = VALVE_SAMPLE_SHADOW(g_tShadowBuffer, float3(shadowMapCenter.xy + g_vShadow3x3PCFTerms1.xw, objDepth)).x; // 1 -1
v20Taps.w = VALVE_SAMPLE_SHADOW(g_tShadowBuffer, float3(shadowMapCenter.xy + g_vShadow3x3PCFTerms1.zw, objDepth)).x; // -1 -1
float flSum = dot(v20Taps.xyzw, float4(0.25, 0.25, 0.25, 0.25));
if ((flSum == 0.0) || (flSum == 1.0))
return flSum;
flSum *= g_vShadow3x3PCFTerms0.x * 4.0;
float4 v33Taps;
v33Taps.x = VALVE_SAMPLE_SHADOW(g_tShadowBuffer, float3(shadowMapCenter.xy + g_vShadow3x3PCFTerms2.xz, objDepth)).x; // 1 0
v33Taps.y = VALVE_SAMPLE_SHADOW(g_tShadowBuffer, float3(shadowMapCenter.xy + g_vShadow3x3PCFTerms3.xz, objDepth)).x; // -1 0
v33Taps.z = VALVE_SAMPLE_SHADOW(g_tShadowBuffer, float3(shadowMapCenter.xy + g_vShadow3x3PCFTerms3.zy, objDepth)).x; // 0 -1
v33Taps.w = VALVE_SAMPLE_SHADOW(g_tShadowBuffer, float3(shadowMapCenter.xy + g_vShadow3x3PCFTerms2.zy, objDepth)).x; // 0 1
flSum += dot(v33Taps.xyzw, g_vShadow3x3PCFTerms0.yyyy);
flSum += VALVE_SAMPLE_SHADOW(g_tShadowBuffer, float3(shadowMapCenter.xy, objDepth)).x * g_vShadow3x3PCFTerms0.z;
return flSum;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------
/**
* Gets the cascade weights based on the world position of the fragment and the positions of the split spheres for each cascade.
* Returns an invalid split index if past shadowDistance (ie 4 is invalid for cascade)
*/
float GetSplitSphereIndexForDirshadows(float3 wpos)
{
float3 fromCenter0 = wpos.xyz - g_vDirShadowSplitSpheres[0].xyz;
float3 fromCenter1 = wpos.xyz - g_vDirShadowSplitSpheres[1].xyz;
float3 fromCenter2 = wpos.xyz - g_vDirShadowSplitSpheres[2].xyz;
float3 fromCenter3 = wpos.xyz - g_vDirShadowSplitSpheres[3].xyz;
float4 distances2 = float4(dot(fromCenter0, fromCenter0), dot(fromCenter1, fromCenter1), dot(fromCenter2, fromCenter2), dot(fromCenter3, fromCenter3));
float4 vDirShadowSplitSphereSqRadii;
vDirShadowSplitSphereSqRadii.x = g_vDirShadowSplitSpheres[0].w;
vDirShadowSplitSphereSqRadii.y = g_vDirShadowSplitSpheres[1].w;
vDirShadowSplitSphereSqRadii.z = g_vDirShadowSplitSpheres[2].w;
vDirShadowSplitSphereSqRadii.w = g_vDirShadowSplitSpheres[3].w;
fixed4 weights = float4(distances2 < vDirShadowSplitSphereSqRadii);
weights.yzw = saturate(weights.yzw - weights.xyz);
return 4 - dot(weights, float4(4, 3, 2, 1));
}
float SampleShadow(uint type, float3 vPositionWs, float3 vPositionToLightDirWs, uint lightIndex)
{
float flShadowScalar = 1.0;
int shadowSplitIndex = 0;
/*if (type == DIRECTIONAL_LIGHT)
{
shadowSplitIndex = GetSplitSphereIndexForDirshadows(vPositionWs);
}
else */if (type == SPHERE_LIGHT)
{
float3 absPos = abs(vPositionToLightDirWs);
shadowSplitIndex = (vPositionToLightDirWs.z > 0) ? CUBEMAPFACE_NEGATIVE_Z : CUBEMAPFACE_POSITIVE_Z;
if (absPos.x > absPos.y)
{
if (absPos.x > absPos.z)
{
shadowSplitIndex = (vPositionToLightDirWs.x > 0) ? CUBEMAPFACE_NEGATIVE_X : CUBEMAPFACE_POSITIVE_X;
}
}
else
{
if (absPos.y > absPos.z)
{
shadowSplitIndex = (vPositionToLightDirWs.y > 0) ? CUBEMAPFACE_NEGATIVE_Y : CUBEMAPFACE_POSITIVE_Y;
}
}
}
flShadowScalar = ComputeShadow_PCF_3x3_Gaussian(vPositionWs.xyz, g_matWorldToShadow[lightIndex * MAX_SHADOWMAP_PER_LIGHT + shadowSplitIndex]);
return flShadowScalar;
}
struct v2f {
float4 vertex : SV_POSITION;

uint l=0;
float3 vPositionWs = mul(g_mViewToWorld, float4(vP, 1));
// we need this outer loop for when we cannot assume a wavefront is 64 wide
// since in this case we cannot assume the lights will remain sorted by type
// during processing in lightlist_cs.hlsl

float3 toLight = vLp - vP;
float dist = length(toLight);
float3 vL = toLight / dist;
float attLookUp = dist*lgtDat.fRecipRange; attLookUp *= attLookUp;
float atten = tex2Dlod(_LightTextureB0, float4(attLookUp.rr, 0.0, 0.0)).UNITY_ATTEN_CHANNEL;

}
atten *= angularAtt*(fProjVec>0.0); // finally apply this to the dist att.
float shadowScalar = SampleShadow(SPOT_LIGHT, vPositionWs, 0, lgtDat.uShadowLightIndex);
atten *= shadowScalar;
UnityLight light;
light.color.xyz = lgtDat.vCol.xyz*atten;

{
atten *= UNITY_SAMPLE_TEXCUBEARRAY_LOD(_pointCookieTextures, float4(-vLw, lgtDat.iSliceIndex), 0.0).w;
}
float shadowScalar = SampleShadow(SPHERE_LIGHT, vPositionWs, vLw, lgtDat.uShadowLightIndex);
atten *= shadowScalar;
UnityLight light;
light.color.xyz = lgtDat.vCol.xyz*atten;

17
Assets/ScriptableRenderLoop/fptl/LightDefinitions.cs


public float fDecodeExp;
public Vec3 vBoxInvRange;
public float fPad0;
public uint uShadowLightIndex;
public Vec3 vLocalCubeCapturePoint;
public float fProbeBlendDistance;

public Vec3 vCen; // a center in camera space inside the bounding volume of the light source.
public Vec2 vScaleXY;
public float fRadius;
};
public struct DirectionalLight
{
public Vec3 vCol;
public float fLightIntensity;
public Vec3 vLaxisX;
public int iSliceIndex;
public Vec3 vLaxisY;
public float fPad0;
public Vec3 vLaxisZ;
public float fPad1;
};
#if !__HLSL

正在加载...
取消
保存