光照基礎
- 環境光
- 漫反射光
- 鏡面光
光照特性
材質屬性
- ?泛射材質
- ?漫反射材質?
- ?鏡面反射材質
- ?發射材質
光照計算
環境光的計算
1. 環境光的計算
? ? ?????環境光 = 光源的環境光顏色 * 物體的材質顏色
2. 環境光GLSL實現
varying vec3 objectColor;
void main()
{
//?至少有%10的光找到物體所有?面
?float ambientStrength = 0.1;
//環境光顏?色
vec3 ambient = ambientStrength * lightColor;
//最終顏?色?=?環境光顏?色?*?物體顏?色
vec3 result = ambient * objectColor;
?l_FragColor = vec4(result, 1.0);
}
發射光的計算
? ? ? ? 發射顏色 = 物體反射材質的顏色
漫反射光的計算
? ??????漫反射顏?色?=?光源的漫反射顏?色?*?物體的漫發射材質顏?色?* DiffuseFactor
? ??????DiffuseFactor = max(0,dot(N,L))
????????漫反射因子DiffuseFactor?是光線與頂點法線向量的點積
? ? ? ? 漫反射光計算代碼實現
? ? ? ? ? ? uniform vec3 lightColor;
? ? ? ? ? ? ?uniform vec3 lightPo;
? ? ? ? ? ? uniform vec3 objectColor;
? ? ? ? ? ? uniform vec3 viewPo;
? ? ? ? ? ? varying vec3 outNormal;
? ? ? ? ? ? //確保法線為單位向量
? ? ? ? ? ?vec3 norm = normalize(outNormal); //頂點指向光源單位向量
? ? ? ? ? ?vec3 lightDir = normalize(lightPo - FragPo); //得到兩向量的cos值小于0則為0
? ? ? ? ? float diff = max(dot(norm, lightDir),0.0); // 得到漫反射收的光源向量
? ? ? ? ? vec3 diffuse = diff * lightColor;
? ? ? ? ? vec3 result? = diffuse * ojbectColor;
? ? ? ? ? gl_FragColor = vec4(result,1.0);
鏡面光計算
N : 平?面法線
?I : 入射光線?
H : 反射光線?
E : 視線
? : 視點與反射光的夾角
鏡面反射顏色?=?光源的鏡面光的顏色?*?物體的鏡面材質顏色?* SpecularFactor
SpecularFactor = power(max(0,dot(N,H)),shininess)
H?:視線向量E?與 光線向量L?的半向量
dot(N,H):H,N的點積幾何意義,平方線與法線夾角的cos值
shiniess :??高光的反光度;
鏡面光計算代碼實現
//鏡面強度
float specularStrength = 0.5;
//頂點指向觀察點的單位向量
vec3 viewDir = normalize(viewPo - FragPo);
//求得光線在頂點的反射線(傳入光源指向頂點的向量)
vec3 reflectDir = reflect(-lightDir ,outNormal);
//?求得夾角cos值取256次冪 注意?pow(float,float)函數參數類型
float spec = pow(max(dot(viewDir, reflectDir),0.0),256.0);
vec3 specular = specularStrength * spec * lightColor;
光照計算
? ??????光照顏色?=(環境顏色?+?漫反射顏色?+?鏡面反射顏色)*?衰減因?
? ? ??
衰減因子
衰減因? = 1.0/(距離衰減常量?+?線性衰減常量?*?距離?+ 二次衰減常量?*?距離的平?)
注意:環境光,漫反射光和鏡面光的強度都會受距離的增大而衰減,只有發射光和全局環境光的強度不會受影響
衰減因子代碼
//距離衰減常量
float constantPara = 1.0f;
//線性衰減常量
float linearPara = 0.09f;
//二次衰減因?
float quadraticPara = 0.032f;
//距離
float LFDistance = length(lightPo - FragPo);
//衰減因?
float lightWeakPara = 1.0/(constantPara + linearPara* LFDistance + quadraticPara (LFDistance*LFDistance));
聚光因子
聚光燈夾角cos值?= power(max(0,dot(單位光源位置,單位光線向量)),聚光燈指數);
- 單位光線向量:從光源指向頂點的單位向量?
- 聚光燈指數:表示聚光燈的亮度程度
- 公式解讀:單位光源位置 *?單位光線向量點積的聚光燈指數次?。
聚光燈過度計算代碼實現
//(?一些復雜的計算操作 應該讓CPU做,提?高效率,不不變的量量也建議外部傳輸,避免 重復計算)
//內錐?角cos值
float inCutOff = cos(radians(10.0f));?
//外錐?角cos值
float outCutOff = cos(radians(15.0f));?
//聚光朝向
vec3 spotDir = vec3(-1.2f,-1.0f,-2.0f);
//光源指向物體的向量和聚光朝向的cos值
float theta = dot(lightDir ,normalize(-spotDir));
?//內外錐角cos差值
float epsilon = inCutOff - outCutOff;
//clamp(a,b,c);若b<a<c則函數返回值為a,若不是則返回最小值b、最大值c
// (theta - outCutOff)/epsilon 若theta的角度小于內錐角 則其值>=1?若theta的角度大于外錐角 則其值<=0?這樣光線就在內外錐角之間平滑變 化.
float intensity = clamp((theta - outCutOff)/epsilon, 0.0,1.0);
光照計算終極公式
光照顏色?=?發射顏色?+?全局環境顏色?+ (環境顏色?+?漫反射顏色?+?鏡?反射顏色) *?聚光燈效果?*?衰減因?
平面光計算代碼實現
//環境因?
float ambientStrength = 0.3;
?//鏡面強度
float specularStrength = 2.0;
?//反射強度
float reflectance = 256.0;
//平行光方向
vec3 paraLightDir = normalize(vec3(-0.2,-1.0,-0.3));
//環境光
vec3 ambient = ambientStrength * texture(Texture ,outTexCoord).rgb;
//漫反射
vec3 norm = normalize(outNormal);
vec3 lightDir = normalize(lightPo - FragPo);?
//當前頂點至光源的的單位向量
float diff = max(dot(norm ,paraLightDir),0.0);
vec3 diffuse = diff * lightColor*texture(Texture ,outTexCoord).rgb;
//鏡面反射
vec3 viewDir = normalize(viewPo - FragPo);
vec3 reflectDir = reflect(-paraLightDir ,outNormal);
float spec = pow(max(dot(viewDir, reflectDir),0.0),reflectance);
vec3 specular = specularStrength * spec * texture(specularTexture ,outTexCoord).rgb;
//最終光照顏色
vec3 res = ambient + diffuse + specular;
FragColor = vec4(res,1.0);
點光源計算代碼實現
float ambientStrength = 0.3;//環境因子
float specularStrength = 2.0;//鏡面強度
float reflectance = 256.0;//反射強度
float constantPara = 1.0f;//常量
float linearPara = 0.09f;//線性部分因子
float quadraticPara = 0.032f; //二次項部分因數
//環境光
vec3 ambient = ambientStrength * texture(Texture ,outTexCoord).rgb;
//漫反射
vec3 norm = normalize(outNormal);
vec3 lightDir = normalize(lightPo - FragPo); //當前頂點至光源的的單位向量
//點光源
float diff = max(dot(norm ,lightDir),0.0); //光源與法線夾?角
vec3 diffuse = diff * lightColor*texture(Texture ,outTexCoord).rgb;
//鏡面反射
vec3 viewDir = normalize(viewPo - FragPo);
vec3 reflectDir = reflect(-lightDir ,outNormal);
float spec = pow(max(dot(viewDir, reflectDir),0.0),reflectance);
vec3 specular = specularStrength * spec * texture(specularTexture ,outTexCoord).rgb;
//光線衰弱
float LFDistance = length(lightPo - FragPo);
float lightWeakPara = 1.0/(constantPara + linearPara * LFDistance + quadraticPara * (LFDistance*LFDistance));
vec3 res = (ambient + diffuse + specular)*lightWeakPara;?
FragColor = vec4(res,1.0);