您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
159 行
5.7 KiB
159 行
5.7 KiB
#ifndef UNITY_COMMON_LIGHTING_INCLUDED
|
|
#define UNITY_COMMON_LIGHTING_INCLUDED
|
|
|
|
// These clamping function to max of floating point 16 bit are use to prevent INF in code in case of extreme value
|
|
float ClampToFloat16Max(float value)
|
|
{
|
|
return min(value, 65504.0);
|
|
}
|
|
|
|
float2 ClampToFloat16Max(float2 value)
|
|
{
|
|
return min(value, 65504.0);
|
|
}
|
|
|
|
float3 ClampToFloat16Max(float3 value)
|
|
{
|
|
return min(value, 65504.0);
|
|
}
|
|
|
|
float4 ClampToFloat16Max(float4 value)
|
|
{
|
|
return min(value, 65504.0);
|
|
}
|
|
|
|
// Ligthing convention
|
|
// Light direction is oriented backward (-Z). i.e in shader code, light direction is -lightData.forward
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Attenuation functions
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Ref: Moving Frostbite to PBR
|
|
float SmoothDistanceAttenuation(float squaredDistance, float invSqrAttenuationRadius)
|
|
{
|
|
float factor = squaredDistance * invSqrAttenuationRadius;
|
|
float smoothFactor = saturate(1.0f - factor * factor);
|
|
return smoothFactor * smoothFactor;
|
|
}
|
|
|
|
#define PUNCTUAL_LIGHT_THRESHOLD 0.01 // 1cm (in Unity 1 is 1m)
|
|
|
|
float GetDistanceAttenuation(float3 unL, float invSqrAttenuationRadius)
|
|
{
|
|
float sqrDist = dot(unL, unL);
|
|
float attenuation = 1.0f / (max(PUNCTUAL_LIGHT_THRESHOLD * PUNCTUAL_LIGHT_THRESHOLD, sqrDist));
|
|
// Non physically based hack to limit light influence to attenuationRadius.
|
|
attenuation *= SmoothDistanceAttenuation(sqrDist, invSqrAttenuationRadius);
|
|
|
|
return attenuation;
|
|
}
|
|
|
|
float GetAngleAttenuation(float3 L, float3 lightDir, float lightAngleScale, float lightAngleOffset)
|
|
{
|
|
float cd = dot(lightDir, L);
|
|
float attenuation = saturate(cd * lightAngleScale + lightAngleOffset);
|
|
// smooth the transition
|
|
attenuation *= attenuation;
|
|
|
|
return attenuation;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// IES Helper
|
|
//-----------------------------------------------------------------------------
|
|
|
|
float2 GetIESTextureCoordinate(float3x3 lightToWord, float3 L)
|
|
{
|
|
// IES need to be sample in light space
|
|
float3 dir = mul(lightToWord, -L); // Using matrix on left side do a transpose
|
|
|
|
// convert to spherical coordinate
|
|
float2 sphericalCoord; // .x is theta, .y is phi
|
|
// Texture is encoded with cos(phi), scale from -1..1 to 0..1
|
|
sphericalCoord.y = (dir.z * 0.5) + 0.5;
|
|
float theta = atan2(dir.y, dir.x);
|
|
sphericalCoord.x = theta * INV_TWO_PI;
|
|
|
|
return sphericalCoord;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Get local frame
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// generate an orthonormalBasis from 3d unit vector.
|
|
void GetLocalFrame(float3 N, out float3 tangentX, out float3 tangentY)
|
|
{
|
|
float3 upVector = abs(N.z) < 0.999 ? float3(0.0, 0.0, 1.0) : float3(1.0, 0.0, 0.0);
|
|
tangentX = normalize(cross(upVector, N));
|
|
tangentY = cross(N, tangentX);
|
|
}
|
|
|
|
// TODO: test
|
|
/*
|
|
// http://orbit.dtu.dk/files/57573287/onb_frisvad_jgt2012.pdf
|
|
void GetLocalFrame(float3 N, out float3 tangentX, out float3 tangentY)
|
|
{
|
|
if (N.z < -0.999) // Handle the singularity
|
|
{
|
|
tangentX = float3(0.0, -1.0, 0.0);
|
|
tangentY = float3(-1.0, 0.0, 0.0);
|
|
return ;
|
|
}
|
|
|
|
float a = 1.0 / (1.0 + N.z);
|
|
float b = -N.x * N.y * a;
|
|
tangentX = float3(1.0f - N.x * N.x * a , b, -N.x);
|
|
tangentY = float3(b, 1.0f - N.y * N.y * a, -N.y);
|
|
}
|
|
*/
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// various helper
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// NdotV should not be negative for visible pixels, but it can happen due to perspective projection and normal mapping + decal
|
|
// In this case this may cause weird artifact.
|
|
// GetNdotV return a 'valid' data
|
|
float GetNdotV(float3 N, float3 V)
|
|
{
|
|
return abs(dot(N, V)); // This abs allow to limit artifact
|
|
}
|
|
|
|
// NdotV should not be negative for visible pixels, but it can happen due to perspective projection and normal mapping + decal
|
|
// In this case normal should be modified to become valid (i.e facing camera) and not cause weird artifacts.
|
|
// but this operation adds few ALU and users may not want it. Alternative is to simply take the abs of NdotV (less correct but works too).
|
|
// Note: This code is not compatible with two sided lighting used in SpeedTree (TODO: investigate).
|
|
float GetShiftedNdotV(float3 N, float3 V)
|
|
{
|
|
// The amount we shift the normal toward the view vector is defined by the dot product.
|
|
float shiftAmount = dot(N, V);
|
|
N = shiftAmount < 0.0 ? N + V * (-shiftAmount + 1e-5f) : N;
|
|
N = normalize(N);
|
|
|
|
return saturate(dot(N, V)); // TODO: this saturate should not be necessary here
|
|
}
|
|
|
|
// 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 'v' after mapping it
|
|
// to a vector within the sphere of radius 'r', where r = sqrt(r2).
|
|
// The vector is originally defined within the cube of dimensions [-r, r]^3.
|
|
// The mapping is performed as per MapCubeToSphere().
|
|
// 'dotV' is dot(v, v) (often calculated when calling such a function)
|
|
float ComputeCubeToSphereMapSqMagnitude(float3 v, float dotV, float r2)
|
|
{
|
|
float3 v2 = v * v;
|
|
return r2 * dotV - 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
|