PBR实践篇

基于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);
}

你可能感兴趣的:(技术美术,游戏,pbr,技术美术,unity,游戏引擎,图形渲染)