基于directx9的PBR光照实现
float4x4 m_WorldMatrix;
float4x4 m_ViewMatrix;
float4x4 m_ProjectionMatrix;
float3 m_Eye;
sampler m_Texture: register(s0);
//sampler m_NormalMap : register(s1);
float4 m_Color;
float m_SpecularPower;
float m_Intensity;
float4 m_SpecularLightColor;
float4 m_AmbientLightColor;
float3 m_LightPos;
float m_Range;
float m_NormalIntensity;
float m_Metallic;
float m_Roughness;//粗糙度
//float m_Ao;//环境光遮蔽
const float PI;
//D:法线分布函数
//表面越光滑,光就越集中,越粗糙,光的范围就会越大,光就越灰暗
float DistributionGGX(float3 N, float3 H, float roughness)
{
//PI = 3.14159265359;
float a = roughness * roughness;
float a2 = a * a;
float NdotH = max(dot(N, H), 0.0);
float NdotH2 = NdotH * NdotH;
float nom = a2;
float denom = (NdotH2 * (a2 - 1.0) + 1.0);
denom = 3.14159265359 * denom * denom;
return nom / denom;
}
//G:几何遮蔽函数
//求得微平面互相遮蔽的比率,互相遮蔽会消耗光线的能量
float GeometrySchlickGGX(float NdotV, float roughness)
{
float r = (roughness + 1.0);
float k = (r * r) / 8.0;
float nom = NdotV;
float denom = NdotV * (1.0 - k) + k;
return nom / denom;
}
float GeomentrySmity(float3 N, float3 V, float3 L, float roughness)
{
float NdotV = max(dot(N, V), 0.0);
float NdotL = max(dot(N, L), 0.0);
float ggx2 = GeometrySchlickGGX(NdotV, roughness);
float ggx1 = GeometrySchlickGGX(NdotL, roughness);
return ggx1 * ggx2;
}
//F:菲涅尔方程=方程中的ks
//cosTheta是表面法向量n与观察方向v的点乘的结果
//反射光线对比光线被折射的部分所占的比率
float3 fresnelSchlick(float cosTheta, float3 fo)
{
return fo + (1 - fo) * pow(clamp(1.0f - cosTheta,0.0f,1.0f), 5.0f);
}
struct Input
{
float3 pos : POSITION0;
float3 normal : NORMAL0;
float2 uv : TEXCOORD;
float3 tangent : TANGENT;
};
struct Output
{
float4 pos : POSITION0;
float3 normal : NORMAL0;
float3 worldPos : TEXCOORD0;
float2 uv : TEXCOORD1;
float3 tangent : TEXCOORD2;
float3 binormal : TEXCOORD3;
float3 lightVec : TEXCOORD4;
float3 camPos : TEXCOORD5;
float3 colos : TEXCOORD6;
};
Output PointVS(Input inPut)
{
Output outPut = (Output)0;
float4x4 worldViewMatrix = mul(m_WorldMatrix, m_ViewMatrix);
float4x4 worldViewProjectionMatrix = mul(worldViewMatrix, m_ProjectionMatrix);
outPut.pos = mul(float4 (inPut.pos.xyz, 1.0f), worldViewProjectionMatrix);
outPut.worldPos = mul(float4 (inPut.pos.xyz, 1.0f), m_WorldMatrix).xyz;
outPut.normal = mul(float4 (inPut.normal, 0.0f), m_WorldMatrix).xyz;
施密特正交化
//outPut.tangent = mul(float4(inPut.tangent.xyz, 0.0f), m_WorldMatrix).xyz;
//outPut.binormal = cross(outPut.normal, outPut.tangent) * inPut.tangent;
outPut.uv = inPut.uv;
//光照向量
outPut.lightVec = m_LightPos.xyz - outPut.worldPos.xyz;
outPut.camPos = m_Eye.xyz - outPut.worldPos.xyz;
return outPut;
}
float4 PointPS(Output inPut) : COLOR
{
m_Metallic = 0.3;//金属度
m_Roughness = 0.3f;//粗糙度
//m_Ao = 0.3f;//环境光遮蔽
inPut.normal = normalize(inPut.normal);
//inPut.tangent = normalize(inPut.tangent);
//inPut.binormal = normalize(inPut.binormal);
float4 albedo = tex2D(m_Texture, inPut.uv);
//float3 sampledNormal = tex2D(m_NormalMap, inPut.uv).xyz;
//sampledNormal = (2.0f * sampledNormal) - 1.0f;
//float3x3 tbn = float3x3(inPut.tangent, inPut.binormal, inPut.normal);
//sampledNormal = mul(sampledNormal, tbn);
inPut.lightVec = normalize(inPut.lightVec);
inPut.camPos = normalize(inPut.camPos);
float3 f0 = 0.04;
//对于非金属材质来说fo应该永远保持0.04这个值
//根据表面金属性来改变f0这个值
//在u和v之间做线性插值,并返回t∈[0, 1]处的值
f0 = lerp(f0, albedo.xyz, m_Metallic);
float3 halfDir = normalize(inPut.lightVec + inPut.camPos);
float distance = length(m_LightPos - inPut.worldPos.xyz);
float attenuation = 1.0 / (distance * distance);
float3 radiance = m_Color.rgb * attenuation;
float NDF = DistributionGGX(inPut.normal, halfDir, m_Roughness);
float G = GeomentrySmity(inPut.normal, inPut.camPos, inPut.lightVec, m_Roughness);
float3 F = fresnelSchlick(clamp(dot(halfDir, inPut.camPos), 0.0f,1.0f), f0);
//return float4(F, 1.0);
float3 nominator = NDF * G * F;
// + 0.0001防止除零
float denominator = 4.0 * max(dot(inPut.normal, inPut.camPos), 0.0f) * max(dot(inPut.normal, inPut.lightVec), 0.0f) + 0.001f;
float3 specular = nominator / denominator*m_SpecularLightColor.rgb;
//return float4(NDF, NDF, NDF, 1.0);
//kS等于菲涅耳
float3 KS = F;
//为了节能,漫射光和镜面光不能
//大于1.0(除非表面发光);为了保护它
//关系扩散分量(kD)应等于1.0 - kS。
float3 KD = (1.0f - KS);
//用kD乘以逆金属性,使只有非金属
//有漫射照明,或线性混合,如果部分金属(纯金属
//没有漫射光)。
KD *= 1.0f - m_Metallic;
//通过NdotL缩放灯光
float NdotL = max(dot(inPut.normal, inPut.lightVec), 0.0f);
float3 L0=0.0f;
//添加到outgoing radiance Lo
//注意,我们已经将BRDF乘以菲涅耳(kS),所以我们不会再乘以kS
L0 += (KD * albedo.xyz / 3.14159265359 + specular)* radiance * NdotL;
//这个环境照明与环境照明)。
//float3 ambient = 0.03 * m_Albedo * m_Ao;
float3 color = L0;
// HDR tonemapping
color = color / (color + 1.0);
// gamma correct
color = pow(abs(color), (1.0 / 2.2));
return float4(color, 1.0);
}