从源头看Dust3d | (十三)Dust3D中的glsl

2021SC@SDUSC

    以scene.frag与scene.vert举例,介绍在渲染管线中的处理。片元着色器主要处理片元的颜色,顶点着色器主要进行坐标系的转换,计算各个顶点的位置

目录

一、光照模式

1.环境光照

2.漫反射

3.镜面反射

二、scene.frag

1.接收从CPU中传递过来的变量

2.计算颜色:通过光照模型进行计算

3.阴影计算

4.主函数

三、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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值