2021SC@SDUSC
以scene.frag与scene.vert举例,介绍在渲染管线中的处理。片元着色器主要处理片元的颜色,顶点着色器主要进行坐标系的转换,计算各个顶点的位置
目录
一、光照模式
1.环境光照
环境光:Iambdiff = Kd*Ia
其中Ia 表示环境光强度,Kd(0<K<1)为材质对环境光的反射系数,Iambdiff是漫反射体与环境光交互反射的光强。
finalColor += qt_Light.ambient.rgb * qt_Material.ambient.rgb;
2.漫反射
采用Lambert模型
对于方向光的漫反射:Ildiff = Kd * Il * Cos(θ)
其中Il是点光源强度,θ是入射光方向与顶点法线的夹角,称入射角(0<=A<=90°),Ildiff是漫反射体与方向光交互反射的光强,若 N为顶点单位法向量,L表示从顶点指向光源的单位向量
vec4 lightDir = vec4( normalize(qt_Light.direction), 0.0 );
//cos θ可以用N和L的点乘来代替
float diffuseFactor = max( c_zero, dot(lightDir, normal) );
if(diffuseFactor > c_zero)
{
finalColor += qt_Light.diffuse.rgb *
qt_Material.diffuse.rgb *
diffuseFactor *
qt_Material.brightness;
}
3.镜面反射
采用Phong模型
Phong模型镜面反射:Ispec = Ks * Il * ( dot(V,R) )^Ns
其中Ks 为镜面反射系数,Ns是高光指数,V表示从顶点到视点的观察方向,R代表反射光方向。
其中反射光的方向R可以通过入射光方向L(从顶点指向光源)和物体的法向量求出,
const vec3 blackColor = vec3(c_zero, c_zero, c_zero);
if( !(qt_Material.specular.rgb == blackColor || qt_Light.specular.rgb == blackColor || qt_Material.specularPower == c_zero) )
{
vec4 viewDir = vec4( normalize(qt_Light.eye), 0.0 );
//反射光方向
vec4 reflectionVec = reflect(lightDir, normal);
//反射光与顶点到视点向量的点乘
float specularFactor = max( c_zero, dot(reflectionVec, -viewDir) );
if(specularFactor > c_zero)
{
specularFactor = pow( specularFactor, qt_Material.specularPower );
finalColor += qt_Light.specular.rgb *
qt_Material.specular.rgb *
specularFactor;
}
}
二、scene.frag
1.接收从CPU中传递过来的变量
通过一样的变量类型以及一样的变量名就可以实现传递
在CPU中:
//分别设定环境反射、漫反射、镜面反射,光源方向以及摄像机(眼睛)的方向
m_sceneProgram->setUniformValue("qt_Light.ambient", QColor(255, 255, 255));
m_sceneProgram->setUniformValue("qt_Light.diffuse", QColor(Qt::white));
m_sceneProgram->setUniformValue("qt_Light.specular", QColor(Qt::white));
m_sceneProgram->setUniformValue("qt_Light.direction", lightDirection);
m_sceneProgram->setUniformValue("qt_Light.eye", eyePosition);
m_sceneProgram->setUniformValue("qt_Material.ambient", ambient);
m_sceneProgram->setUniformValue("qt_Material.diffuse", diffuse);
m_sceneProgram->setUniformValue("qt_Material.specular", specular);
m_sceneProgram->setUniformValue("qt_Material.specularPower", 0.0f);
m_sceneProgram->setUniformValue("qt_Material.brightness", 1.0f);
m_sceneProgram->setUniformValue("qt_Material.opacity", 1.0f);
在GLSL中:
struct directional_light
{
vec3 direction;
vec3 eye;
vec4 ambient;
vec4 diffuse;
vec4 specular;
};
struct material_properties
{
vec4 ambient;
vec4 diffuse;
vec4 specular;
float specularPower;
float opacity;
float brightness;
};
uniform directional_light qt_Light;
uniform material_properties qt_Material;
uniform sampler2D qt_ShadowMap;
uniform bool qt_ShadowEnabled;
2.计算颜色:通过光照模型进行计算
vec4 evaluateLightMaterialColor(in vec4 normal)
{
// Start with black color
vec3 finalColor = vec3(c_zero, c_zero, c_zero);
// 环境光
finalColor += qt_Light.ambient.rgb * qt_Material.ambient.rgb;
// 漫反射
vec4 lightDir = vec4( normalize(qt_Light.direction), 0.0 );
//cos θ可以用N和L的点乘来代替
float diffuseFactor = max( c_zero, dot(lightDir, normal) );
if(diffuseFactor > c_zero)
{
finalColor += qt_Light.diffuse.rgb *
qt_Material.diffuse.rgb *
diffuseFactor *
qt_Material.brightness;
}
//镜面反射,Phong模型
const vec3 blackColor = vec3(c_zero, c_zero, c_zero);
if( !(qt_Material.specular.rgb == blackColor || qt_Light.specular.rgb == blackColor || qt_Material.specularPower == c_zero) )
{
vec4 viewDir = vec4( normalize(qt_Light.eye), 0.0 );
//反射光方向
vec4 reflectionVec = reflect(lightDir, normal);
//反射光与顶点到视点向量的点乘
float specularFactor = max( c_zero, dot(reflectionVec, -viewDir) );
if(specularFactor > c_zero)
{
specularFactor = pow( specularFactor, qt_Material.specularPower );
finalColor += qt_Light.specular.rgb *
qt_Material.specular.rgb *
specularFactor;
}
}
//opacity为材质的不透明度
return vec4( finalColor, qt_Material.opacity );
}
3.阴影计算
相机空间中的深度值计算公式为
公式详细推导过程借鉴:深度缓冲中的深度值计算及可视化 - 知乎
阴影的计算通过比较深度值来看哪部分应该变成阴影,哪部分应该呈现出来
float linearizeDepth(float depth)
{
float z = depth * 2.0 - 1.0; // Back to NDC
return (2.0 * c_zNear * c_ZFar) / (c_ZFar + c_zNear - z * (c_ZFar - c_zNear));
}
float evaluateShadow(in vec4 shadowPos)
{
vec3 shadowCoords = shadowPos.xyz / shadowPos.w;
shadowCoords = shadowCoords * c_half + c_half;
if(shadowCoords.z > c_one)
return c_one;
float currentDepth = shadowPos.z;
float shadow = c_zero;
const int sampleRange = 2;
const float nrSamples = (2.0*float(sampleRange) + 1.0)*(2.0*float(sampleRange) + 1.0);
for(int x=-sampleRange; x<=sampleRange; x++)
{
for(int y=-sampleRange; y<=sampleRange; y++)
{
vec2 pcfCoords = shadowCoords.xy + vec2(x,y)*texelSize;
float pcfDepth = linearizeDepth( texture2D(qt_ShadowMap, pcfCoords).r );
shadow += (currentDepth < pcfDepth) ? c_one : c_half;
}
}
shadow /= nrSamples;
return shadow;
}
4.主函数
调用以上函数得到片元的颜色(通过综合光照与阴影得到)
void main(void)
{
vec4 lmColor = evaluateLightMaterialColor(v_Normal);
if(qt_ShadowEnabled == true)
{
float shadow = evaluateShadow(v_ShadowPosition);
gl_FragColor = vec4(lmColor.xyz * shadow, qt_Material.opacity);
}
else
gl_FragColor = lmColor;
}
三、scene.vert
进行空间转换,计算每个顶点的位置
void main(void)
{
v_Normal = normalize(qt_NormalMatrix * qt_Normal);
v_ShadowPosition = qt_LightViewProjectionMatrix * vec4(qt_Vertex.xyz, 1.0);
gl_Position = qt_ModelViewProjectionMatrix * qt_Vertex;
}