美文网首页
OpenGL ES 光照

OpenGL ES 光照

作者: 神迹12 | 来源:发表于2021-06-12 21:32 被阅读0次

冯氏光照

冯氏光照模型(Phong Lighting Model))的主要结构由3个分量组成:环境(Ambient)、漫反射(Diffuse)和镜面(Specular)光照。

image.png

环境光照(Ambient Lighting):即使在黑暗的情况下,世界上通常也仍然有一些光亮(月亮、远处的光),所以物体几乎永远不会是完全黑暗的。为了模拟这个,我们会使用一个环境光照常量,它永远会给物体一些颜色。
漫反射光照(Diffuse Lighting):模拟光源对物体的方向性影响(Directional Impact)。它是冯氏光照模型中视觉上最显著的分量。物体的某一部分越是正对着光源,它就会越亮。
镜面光照(Specular Lighting):模拟有光泽物体上面出现的亮点。镜面光照的颜色相比于物体的颜色会更倾向于光的颜色。

我们在现实生活中看到某一物体的颜色并不是这个物体真正拥有的颜色,而是它所反射的(Reflected)颜色。换句话说,那些不能被物体所吸收(Absorb)的颜色(被拒绝的颜色)就是我们能够感知到的物体的颜色。

白光照在蓝色的玩具上,蓝色的玩具会吸收白光中除了蓝色以外的所有子颜色,不被吸收的蓝色光被反射到我们的眼中。我们可以使用不同的光源颜色来让物体显现出意想不到的颜色。

当把光源的颜色与物体的颜色值相乘,所得到的就是这个物体所反射的颜色才是我们所感知到的颜色。

1 环境光照

环境光照可以简化成用光的颜色乘以一个很小的常量环境因子,再乘以物体的颜色,然后将最终结果作为片段的颜色。

    float ambientStrength = 0.3;
    vec3 lightColor = vec3(1.0, 1.0, 1.0);
    // 环境光照
    vec3 ambient = ambientStrength * lightColor;

2 漫反射

image.png

漫反射光照计算需要:
1、法向量:一个垂直于顶点表面的向量。
2、定向的光线:作为光源的位置与片段的位置之间向量差的方向向量。

varying vec3 fragPos;//当前片段坐标
varying vec3 norm;//当前片段法向量(归一化处理)
uniform vec3 aLightPos;//光源位置
    //材质漫反射系数
    float diffuseStrength = 0.5;
    // 归一化光源线
    vec3 lightDir = normalize(aLightPos - fragPos);
    // norm是片段表面的法向量
    float diff = max(dot(norm, lightDir), 0.0);
    vec3 diffuse = diff * lightColor;

向量需要都是标准化的,保证点乘得到余弦值,用点乘结果计算光线对片段颜色的影响。点乘结果和0比较,避免漫反射分量为负数。

向量点乘

image.png
两个向量的点乘等于它们的数乘结果乘以两个向量之间夹角的余弦值。

3 镜面反射

image.png
    // 镜面光照
    float specularStrength = 2.5;
    //vec3 viewDir = normalize(viewPos - FragPos); //视线方向向量 
   //在观察空间计算,观察者的位置总是(0, 0, 0),
    vec3 viewDir = normalize(-fragPos);
    // lightDir向量进行了取反。reflect函数要求第一个向量是从光源指向片段位置的向量
    vec3 reflectDir = reflect(-lightDir, norm);
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), 16.0);
    vec3 specular = spec * specularStrength * lightColor;

    vec4 textColor = texture2D(texture,TexCoord);

如何理解reflect的计算:

lightDir方向.png 入射光及反射光.png

如上2幅图可以看到lightDir方向以及,-lightDir方向。-lightDir作为入射光,根据法向量n,计算出发射光向量reflectDir。

我们选择在世界空间进行光照计算,但是大多数人趋向于在观察空间进行光照计算。在观察空间计算的好处是,观察者的位置总是(0, 0, 0),所以这样你直接就获得了观察者位置。可是我发现在学习的时候在世界空间中计算光照更符合直觉。如果你仍然希望在观察空间计算光照的话,你需要将所有相关的向量都用观察矩阵进行变换(记得也要改变法线矩阵)。

如果要在观察空间进行光照计算,则将相关向量进行model和view矩阵变换。

顶点着色器代码:

uniform mat4 uMVMatrix;
uniform mat4 uMVPMatrix;

attribute vec4 aPosition;
// 法向量
attribute vec3 aNormal;
attribute vec3 objectColor;

varying vec3 fragPos;
varying vec3 norm;

// 纹理坐标
attribute vec2 aTexCoords;
varying vec2 TexCoord;

void main() {
    // 乘以model view矩阵(uMVMatrix),转换到观察空间
    fragPos = vec3(uMVMatrix * aPosition);
    norm = normalize(vec3(uMVMatrix * vec4(aNormal, 0.0)));
    gl_Position = uMVPMatrix * aPosition;
    // 纹理坐标
    TexCoord = aTexCoords;
}

片元着色器代码:

precision mediump float;
varying vec2 TexCoord;
varying vec3 fragPos;
varying vec3 norm;
uniform vec3 aLightPos;
uniform sampler2D texture;
void main() {
    //1--- 环境光照
    float ambientStrength = 0.3;
    vec3 lightColor = vec3(1.0, 1.0, 1.0);
    vec3 ambient = ambientStrength * lightColor;
    //2-- 漫反射光照
    //材质漫反射系数
    float diffuseStrength = 0.5;
    // 归一化光源线
    vec3 lightDir = normalize(aLightPos - fragPos);
    float diff = max(dot(norm, lightDir), 0.0);
    vec3 diffuse = diffuseStrength*diff * lightColor;

    //3-- 镜面光照
    float specularStrength = 2.5;
    //vec3 viewDir = normalize(viewPos - FragPos); //视线方向向量
    vec3 viewDir = normalize(-fragPos);//在观察空间计算的好处是,观察者的位置总是(0, 0, 0),
    // lightDir向量进行了取反。reflect函数要求第一个向量是从光源指向片段位置的向量
    vec3 reflectDir = reflect(-lightDir, norm);
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), 16.0);
    vec3 specular = spec * specularStrength * lightColor;

    vec4 textColor = texture2D(texture,TexCoord);

    // 结果
    vec3 result = (ambient + diffuse + specular) * vec3(textColor);//-- 1颜色
    gl_FragColor = vec4(result, 1.0);
}

4 效果

image.png

参考
https://learnopengl-cn.github.io/02%20Lighting/02%20Basic%20Lighting/
https://blog.csdn.net/jklwan/article/details/103633239?spm=1001.2014.3001.5501
https://learnopengl-cn.github.io/01%20Getting%20started/07%20Transformations/
https://blog.csdn.net/jklwan/article/details/103744812?spm=1001.2014.3001.5501

相关文章

  • OpenGL ES 光照

    冯氏光照 冯氏光照模型(Phong Lighting Model))的主要结构由3个分量组成:环境(Ambient...

  • OpenGL/OpenGL ES (九) —— 光照

    OpenGL/OpenGL ES (一) —— 专业名词快速了解OpenGL/OpenGL ES (二) —— 渲...

  • OpenGL ES(五) 光照

    在OpenGL ES中光照模型主要结构由3个元素组成:环境(Ambient)光照、漫反射(Diffuse)光照和镜...

  • 02总结--014--OpenGL ES 初识

    OpenGL ES 初识 OpenGL ES 简介 OpenGL ES (OpenGL for Embedded ...

  • OpenGL ES光照计算

    光照是OpenGL ES里很重要的一部分,下面我们来学习总结一下如何计算不同的光照效果。 光照基础1、环境光照2、...

  • OpenGL ES 􏳆􏰤􏷐􏶾􏲗􏵘光照计算

    光照基础 环境光 漫反射光 镜面光 光照特性 发射光:由物体自身发光 环境光:环境中充分散射的光,而且无法分辨它的...

  • OpenGL ES光照计算

    光照基础 环境光照:利用环境光可以描述一块区域的亮度,通常在场景中,环境光的颜色是一个常量 漫反射光照:光线向所有...

  • OpenGL ES 光照计算

    冯氏光照模型:主要结构由3个元素组成:环境(Ambient)光照、漫反射(Diffuse)光照和镜面(Specul...

  • OPenGL ES光照计算

    现实世界的光照是极其复杂的,而且会受到诸多因素的影响,这是以目前我们所拥有的处理能力无法模拟的。因此OpenGL的...

  • OpenGL ES 光照计算

    光照计算在片元着色器执行,计算每一个像素点的颜色 一、光照计算 1、环境光计算 环境光 = 光源的环境光颜色 * ...

网友评论

      本文标题:OpenGL ES 光照

      本文链接:https://www.haomeiwen.com/subject/hdemeltx.html