浏览代码

Merge pull request #27 from EvgeniiG/master

Improvements and fixes for the sky, IBL and area lights
/main
GitHub 8 年前
当前提交
fd4b83fe
共有 7 个文件被更改,包括 124 次插入71 次删除
  1. 11
      Assets/ScriptableRenderLoop/HDRenderLoop/HDRenderLoop.cs
  2. 3
      Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/SinglePass/SinglePass.hlsl
  3. 3
      Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/SinglePass/SinglePassLoop.hlsl
  4. 78
      Assets/ScriptableRenderLoop/HDRenderLoop/Material/Lit/Lit.hlsl
  5. 1
      Assets/ScriptableRenderLoop/HDRenderLoop/Material/Material.hlsl
  6. 2
      Assets/ScriptableRenderLoop/HDRenderLoop/Sky/SkyRenderer.cs
  7. 97
      Assets/ScriptableRenderLoop/ShaderLibrary/CommonLighting.hlsl

11
Assets/ScriptableRenderLoop/HDRenderLoop/HDRenderLoop.cs


//Shader.SetGlobalTexture("_CookieTextures", m_CookieTexArray.GetTexCache());
//Shader.SetGlobalTexture("_CubeCookieTextures", m_CubeCookieTexArray.GetTexCache());
Shader.SetGlobalTexture("_EnvTextures", m_CubeReflTexArray.GetTexCache());
m_SkyRenderer.SetGlobalSkyTexture();
if (m_SkyRenderer.IsSkyValid(m_SkyParameters))
{
m_SkyRenderer.SetGlobalSkyTexture();
Shader.SetGlobalInt("_EnvLightSkyEnabled", 1);
}
else
{
Shader.SetGlobalInt("_EnvLightSkyEnabled", 0);
}
if (debugParameters.useSinglePassLightLoop)
{

3
Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/SinglePass/SinglePass.hlsl


uint _PunctualLightCount;
uint _AreaLightCount;
uint _EnvLightCount;
int _EnvLightSkyEnabled; // TODO: make it a bool
float4 _DirShadowSplitSpheres[4]; // TODO share this max between C# and hlsl
float4 _DirShadowSplitSpheres[4]; // TODO: share this max between C# and hlsl
CBUFFER_END
struct LightLoopContext

3
Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/SinglePass/SinglePassLoop.hlsl


iblSpecularLighting = lerp(iblSpecularLighting, localSpecularLighting, weight.y);
}
// Sky Ibl
// Only apply sky IBL if the sky texture is available.
if (_EnvLightSkyEnabled)
{
float3 localDiffuseLighting, localSpecularLighting;
float2 weight;

78
Assets/ScriptableRenderLoop/HDRenderLoop/Material/Lit/Lit.hlsl


// Aniso
float TdotV;
float BdotV;
// image based lighting
// These variables aim to be use with EvaluateBSDF_Env
float3 iblNormalWS; // Normal to be use with image based lighting
float3 iblR; // Reflection vector, same as above.
float3 iblDirWS; // Dominant specular direction, used for IBL in EvaluateBSDF_Env()
float3 specularFGD; // Store preconvole BRDF for both specular and diffuse
float diffuseFGD;

preLightData.ggxLambdaV = GetSmithJointGGXLambdaV(preLightData.NdotV, bsdfData.roughness);
float iblNdotV = preLightData.NdotV;
float iblNdotV = preLightData.NdotV;
float3 iblNormalWS = bsdfData.normalWS;
// Check if we precompute anisotropy too

preLightData.anisoGGXLambdaV = GetSmithJointGGXAnisoLambdaV(preLightData.TdotV, preLightData.BdotV, preLightData.NdotV, bsdfData.roughnessT, bsdfData.roughnessB);
// Tangent = highlight stretch (anisotropy) direction. Bitangent = grain (brush) direction.
iblNormalWS = GetAnisotropicModifiedNormal(bsdfData.bitangentWS, bsdfData.normalWS, V, bsdfData.anisotropy);
// NOTE: If we follow the theory we should use the modified normal for the different calculation implying a normal (like NDotV) and use iblNormalWS
// into function like GetSpecularDominantDir(). However modified normal is just a hack. The goal is just to stretch a cubemap, no accuracy here.
// With this in mind and for performance reasons we chose to only use modified normal to calculate R.

// We need to take into account the modified normal for faking anisotropic here.
preLightData.iblR = reflect(-V, iblNormalWS);
// We need to take into account the modified normal for faking anisotropic here.
float3 iblR = reflect(-V, iblNormalWS);
preLightData.iblDirWS = GetSpecularDominantDir(bsdfData.normalWS, iblR, bsdfData.roughness);
// #if SHADERPASS == SHADERPASS_GBUFFER
// preLightData.ambientOcclusion = LOAD_TEXTURE2D(_AmbientOcclusion, coord.unPositionSS).x;

float3 unL = positionWS - lightData.positionWS;
// Pick the axis along which to expand the fade-out sphere into an ellipsoid.
// Pick the major axis of the ellipsoid.
// We define the ellipsoid s.t. r1 = r, r2 = (r + len / 2).
// We define the ellipsoid s.t. r1 = (r + len / 2), r2 = r3 = r.
// TODO: This could be precomputed.
float radius = rsqrt(lightData.invSqrAttenuationRadius);
float invAspectRatio = radius / (radius + (0.5 * len));

// EvaluateBSDF_Area - Approximation with Linearly Transformed Cosines
//-----------------------------------------------------------------------------
// #define ELLIPSOIDAL_ATTENUATION
void EvaluateBSDF_Area(LightLoopContext lightLoopContext,
float3 V, float3 positionWS,
PreLightData preLightData, LightData lightData, BSDFData bsdfData,

float3 unL = positionWS - lightData.positionWS;
// Pick the axis along which to expand the fade-out sphere into an ellipsoid.
float3 axis = (halfWidth >= halfHeight) ? lightData.right : lightData.up;
// Rotate the light direction into the light space.
float3x3 lightToWorld = float3x3(lightData.right, lightData.up, lightData.forward);
unL = mul(unL, transpose(lightToWorld));
// We define the ellipsoid s.t. r1 = r, r2 = (r + |w - h| / 2).
// Define the dimensions of the attenuation volume.
float radius = rsqrt(lightData.invSqrAttenuationRadius);
float invAspectRatio = radius / (radius + abs(halfWidth - halfHeight));
float radius = rsqrt(lightData.invSqrAttenuationRadius);
float3 invHalfDim = rcp(float3(radius + halfWidth,
radius + halfHeight,
radius));
float intensity = GetEllipsoidalDistanceAttenuation(unL, lightData.invSqrAttenuationRadius,
axis, invAspectRatio);
#ifdef ELLIPSOIDAL_ATTENUATION
// The attenuation volume is an axis-aligned ellipsoid s.t.
// r1 = (r + w / 2), r2 = (r + h / 2), r3 = r.
float intensity = GetEllipsoidalDistanceAttenuation(unL, invHalfDim);
#else
// The attenuation volume is an axis-aligned box s.t.
// hX = (r + w / 2), hY = (r + h / 2), hZ = r.
float intensity = GetBoxDistanceAttenuation(unL, invHalfDim);
#endif
// Terminate if the shaded point is too far away.
if (intensity == 0.0) return;

// TODO: test the strech from Tomasz
// float shrinkedRoughness = AnisotropicStrechAtGrazingAngle(bsdfData.roughness, bsdfData.perceptualRoughness, NdotV);
// Note: As explain in GetPreLightData we use normalWS and not iblNormalWS here (in case of anisotropy)
float3 rayWS = GetSpecularDominantDir(bsdfData.normalWS, preLightData.iblR, bsdfData.roughness);
float3 R = rayWS;
weight = float2(1.0, 1.0);
// In Unity the cubemaps are capture with the localToWorld transform of the component.
// In Unity the cubemaps are capture with the localToWorld transform of the component.
float3 R = preLightData.iblDirWS;
float3x3 worldToLocal = transpose(float3x3(lightData.right, lightData.up, lightData.forward)); // worldToLocal assume no scaling
float3 positionLS = positionWS - lightData.positionWS;
positionLS = mul(positionLS, worldToLocal).xyz - lightData.offsetLS; // We want to calculate the intersection from the center of the bounding box.

float3 rayLS = mul(rayWS, worldToLocal);
float3 dirLS = mul(preLightData.iblDirWS, worldToLocal);
float dist = BoxRayIntersectSimple(positionLS, rayLS, -boxOuterDistance, boxOuterDistance);
float dist = BoxRayIntersectSimple(positionLS, dirLS, -boxOuterDistance, boxOuterDistance);
R = (positionWS + dist * rayWS) - lightData.positionWS;
R = (positionWS + dist * preLightData.iblDirWS) - lightData.positionWS;
}
}
float3 rayLS = mul(rayWS, worldToLocal);
float3 dirLS = mul(preLightData.iblDirWS, worldToLocal);
float dist = SphereRayIntersectSimple(positionLS, rayLS, sphereOuterDistance);
float dist = SphereRayIntersectSimple(positionLS, dirLS, sphereOuterDistance);
R = (positionWS + dist * rayWS) - lightData.positionWS;
R = (positionWS + dist * preLightData.iblDirWS) - lightData.positionWS;
weight.y = 1.0;
if (lightData.envShapeType == ENVSHAPETYPE_SPHERE)
{
float distFade = max(length(positionLS) - lightData.innerDistance.x, 0.0);

1
Assets/ScriptableRenderLoop/HDRenderLoop/Material/Material.hlsl


#include "GeometricTools.hlsl"
#include "CommonMaterial.hlsl"
#include "EntityLighting.hlsl"
#include "ImageBasedLighting.hlsl"
//-----------------------------------------------------------------------------
// BuiltinData

2
Assets/ScriptableRenderLoop/HDRenderLoop/Sky/SkyRenderer.cs


}
bool IsSkyValid(SkyParameters parameters)
public bool IsSkyValid(SkyParameters parameters)
{
// Later we will also test shader for procedural skies.
return parameters.skyHDRI != null;

97
Assets/ScriptableRenderLoop/ShaderLibrary/CommonLighting.hlsl


// Light direction is oriented backward (-Z). i.e in shader code, light direction is -lightData.forward
//-----------------------------------------------------------------------------
// Helper functions
//-----------------------------------------------------------------------------
// Performs the mapping of the vector 'v' centered within the axis-aligned cube
// of dimensions [-1, 1]^3 to a vector centered within the sphere of radius 1.
// The function expects 'v' to be within the cube (possibly unexpected results otherwise).
// Ref: http://mathproofs.blogspot.com/2005/07/mapping-cube-to-sphere.html
float3 MapCubeToSphere(float3 v)
{
float3 v2 = v * v;
float2 vr3 = v2.xy * rcp(3.0);
return v * sqrt((float3)1.0 - 0.5 * v2.yzx - 0.5 * v2.zxy + vr3.yxx * v2.zzy);
}
// Computes the squared magnitude of the vector computed by MapCubeToSphere().
float ComputeCubeToSphereMapSqMagnitude(float3 v)
{
float3 v2 = v * v;
// Note: dot(v, v) is often computed before this function is called,
// so the compiler should optimize and use the precomputed result here.
return dot(v, v) - v2.x * v2.y - v2.y * v2.z - v2.z * v2.x + v2.x * v2.y * v2.z;
}
//-----------------------------------------------------------------------------
// Attenuation functions
//-----------------------------------------------------------------------------

return attenuation;
}
// Applies SmoothDistanceAttenuation() after stretching the fade-out sphere of the given radius
// into an ellipsoid with the specified aspect ratio and the longest axis.
// Applies SmoothDistanceAttenuation() after transforming the attenuation ellipsoid into a sphere
// of the given radius. The process is performed along the major axis of the ellipsoid, and
// the magnitude of the transformation is controlled by the aspect ratio (the inverse is given).
// Both the ellipsoid (e.i. 'axis') and 'unL' should be in the same coordinate system.
// 'unL' should be computed from the center of the ellipsoid.
// Project the unnormalized light vector onto the expansion axis.
// Project the unnormalized light vector onto the axis.
// We want 'unL' to shrink along 'axis' by the aspect ratio. Therefore, we compute
// the difference between the length of the original projection and the shrunk one.
// It is equivalent to the expansion of the fade-out sphere into an ellipsoid.
float scale = projL - projL * invAspectRatio;
unL -= scale * axis;
// Transform the light vector instead of transforming the ellipsoid.
float diff = projL - projL * invAspectRatio;
unL -= diff * axis;
float sqDist = dot(unL, unL);
return SmoothDistanceAttenuation(sqDist, invSqrAttenuationRadius);
}
// Applies SmoothDistanceAttenuation() using the axis-aligned ellipsoid of the given dimensions.
// Both the ellipsoid and 'unL' should be in the same coordinate system.
// 'unL' should be computed from the center of the ellipsoid.
float GetEllipsoidalDistanceAttenuation(float3 unL, float3 invHalfDim)
{
// Transform the light vector so that we can work with
// with the ellipsoid as if it was a unit sphere.
unL *= invHalfDim;
float sqDist = dot(unL, unL);
return SmoothDistanceAttenuation(sqDist, 1.0);
}
// Applies SmoothDistanceAttenuation() after mapping the axis-aligned box to a sphere.
// If the diagonal of the box is 'd', invHalfDim = rcp(0.5 * d).
// Both the box and 'unL' should be in the same coordinate system.
// 'unL' should be computed from the center of the box.
float GetBoxDistanceAttenuation(float3 unL, float3 invHalfDim)
{
// Transform the light vector so that we can work with
// with the box as if it was a [-1, 1]^2 cube.
unL *= invHalfDim;
return SmoothDistanceAttenuation(dot(unL, unL), invSqrAttenuationRadius);
// Our algorithm expects the input vector to be within the cube.
if (Max3(abs(unL.x), abs(unL.y), abs(unL.z)) > 1.0) return 0.0;
float sqDist = ComputeCubeToSphereMapSqMagnitude(unL);
return SmoothDistanceAttenuation(sqDist, 1.0);
}
//-----------------------------------------------------------------------------

tangentY = float3(b, 1.0f - N.y * N.y * a, -N.y);
}
*/
//-----------------------------------------------------------------------------
// various helper
//-----------------------------------------------------------------------------
// Performs the mapping of the vector 'v' located within the cube of dimensions [-r, r]^3
// to a vector within the sphere of radius 'r', where r = sqrt(r2).
// Modified version of http://mathproofs.blogspot.com/2005/07/mapping-cube-to-sphere.html
float3 MapCubeToSphere(float3 v, float r2)
{
float3 v2 = v * v;
float2 vr3 = v2.xy * rcp(3.0 * r2);
return v * sqrt((float3)r2 - 0.5 * v2.yzx - 0.5 * v2.zxy + vr3.yxx * v2.zzy);
}
// Computes the squared magnitude of the vector computed by MapCubeToSphere().
float ComputeCubeToSphereMapSqMagnitude(float3 v, float r2)
{
float3 v2 = v * v;
// Note: dot(v, v) is often computed before this function is called,
// so the compiler should optimize and use the precomputed result here.
return r2 * dot(v, v) - v2.x * v2.y - v2.y * v2.z - v2.z * v2.x + v2.x * v2.y * v2.z * rcp(r2);
}
#endif // UNITY_COMMON_LIGHTING_INCLUDED
正在加载...
取消
保存