精华内容
下载资源
问答
  • 从理论上详细计算了在全内反射的条件下,两束入射产生的隐失干涉场(即隐失驻波)的强度分布,并分析了其不同于传统传播波干涉场的特点。同时使用数值模拟证明了利用隐失干涉场,即隐失驻波的激发方式,可以提高系统的...
  • ε接近零的平板反射光增强的Imbert-Fedorov效果
  • OpenGL 镜面反射光

    千次阅读 2017-05-07 17:08:12
    背景 ...我们在计算环境的时候,的强度是唯一的影响因素。然后处理漫射的时候...镜面反射时光以一定角度照射到物体表面,同时会在法线的另一侧对称的角度上反射出去,如果观察者刚好在反射光线的路径上那

    转载地址:http://www.2cto.com/kf/201611/561551.html

    背景

    我们在计算环境光的时候,光的强度是唯一的影响因素。然后处理漫射光的时候公式中加入了光的方向参数。镜面反射包含了上面所有的综合因素并且添加了一个新的元素:观察者的位置。镜面反射时光以一定角度照射到物体表面,同时会在法线的另一侧对称的角度上反射出去,如果观察者刚好在反射光线的路径上那么就会看到格外强烈的光线。

    镜面反射最终的结果是物体在从某个角度看上去会十分明亮,而移动开后这个光亮又会消失。现实中好的镜面反射的例子是金属物体,这些物体有时候看上去由于太亮了导致看不到他本来的颜色而是直接照向你眼睛的白色的亮光。但这种属性在其他的一些材料上是没有的(比如:木头)。很多东西根本不会发光,不管光源从什么角度照射以及观察者在什么位置。所以,镜面反射光的存在更取决于反射物体的材料性质而不是光源本身。

    现在看如何将观察者的位置加入到镜面反射光的计算当中,看下图:

    要注意五个因素:

    ‘I’ 是入射光

    ‘N’ 是表面法线

    ‘R’ 反射光,和入射光’I’关于法线对称,但方向相反

    ‘V’ 是从入射光和反射光交点处(入射点)到观察者眼睛的向量,表示观察者视线

    ‘α’ 反射光’R’和观察者视线’V’的夹角

    我们将使用夹角’α’来对镜面反射光现象进行建模。有一点可以看出当观察者视线和反射光重合时(夹角为0),反射光的强度最大。观察者慢慢从反射光’R’移开时,夹角慢慢变大,而我们希望随着角度增大反射光要慢慢衰弱。明显,这里又要使用差积运算来计算夹角’α’的余弦值了,这个值将作为计算镜面反射光公式的反射参数。当’α’为0时余弦值为1,这是我们反射参数的最大值。随着夹角’α’增大余弦值慢慢减小,直到夹角达到90度时就彻底没有镜面反射的效果了。当然,夹角大于90度时余弦值为负,也没有任何反射效果,也就是观察者不在反射光的路径范围内。

    我们要用到’R’和’V’来计算夹角’α’。’V’可以通过世界坐标系中观察者位置和光的入射点位置的差计算得到。camera已经在世界空间进行维护了,我们只需要将它的位置传给shader着色器。另外上面的图是经过简化了的模型,光在物体表面只有一个入射点(事实上不是,这里只是为了好分析)。事实上,整个三角形都被点亮了(假设它面向光源),因此我们要计算每一个像素的镜面反射效果(和漫反射光的计算一样)。我们必须要知道每个像素在世界空间的位置,这个不难:可以将顶点变换到世界空间,让光栅器对像素的世界空间位置进行插值并将结果传给片段着色器。事实上,这个和之前教程中对法线的处理操作是一样的。

    最后是要使用’I’向量(由应用传给shader)来计算反射光线’R’。如下图:

    首先要强调向量没有起点的概念,所有方向相同且长度相同的向量都是同一个向量。因此,图中将入射光向量’I’复制到表面下面位置向量本身是不变的。目标是求向量’R’,根据向量的加法,’R’等于’I’+’V’。’I’是已知的,所以我们要求’V’。注意法线’N’的反向向量为’-N’,计算’I’和’-N’的点积可以得到’I’在’-N’上的投影,这也是’V’的模长度的一半。另外’V’和’N’的方向是相同的,所以只要用计算的那个投影长度乘以单位向量’N’再乘以2就是向量’V’了。用公式简单表示如下:

    明白这个数学公式后可以说一个相关的知识点:GLSL提供了一个叫做’reflect’的内部函数就是做的上面这个计算。可以看下面这个函数在shader中的用法。这里得出计算镜面反射的最终公式:

    开始先是将光的颜色和物体表面的颜色相乘,这个和在计算环境光以及漫反射光时一样。得到的结果再和材料的镜面反射强度参数(’M’)相乘。如果材料没有反射性能,比如木头,那么镜面反射参数就为0,整个公式的结果也就为0了,而像金属这种发光材料镜面反射能力就会很强。之后再乘以光线和观察者视线夹角的余弦值,这也是最后一个调整镜面反射光强度的参数(‘镜面参数’或者叫做‘发光参数’)。镜面参数是用来增强加剧反射光区域边缘的强度的。下面的图片展示了镜面参数为1时的效果:

    下面的镜面参数为32:

    镜面反射能力也被认为是材料的一种属性,因此不同的物体会有不同的镜面反射能力值。

    源代码详解

    (lighting_technique.h:32)

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class LightingTechnique : public Technique
    {
    public :
    ...
         void SetEyeWorldPos( const Vector3f& EyeWorldPos);
         void SetMatSpecularIntensity( float Intensity);
         void SetMatSpecularPower( float Power);
     
    private :
    ...
         GLuint m_eyeWorldPosLocation;
         GLuint m_matSpecularIntensityLocation;
         GLuint m_matSpecularPowerLocation;
    }

    LightingTechnique类中有了三个新属性:眼睛(观察者)的位置、镜面反射强度和材料的镜面参数。这三个参数都是独立于光线本身的,因为当同一束光照到不同的材料上(比如:木头和金属)时会有不同的反射发光效果。目前对材料属性的的使用模型还是很局限的,同一个绘制回调的所有三角形会得到这些属性的一样的值。如果同一个模型的不同部分的三角形图元是不同的材料,这样就不合理了。在后面的教程中讲关于mesh网格的加载时我们会在一个模块中产生不同的镜面参数值并作为顶点缓冲器的一部分(而不是shader的一个参数),这样我们就可以在同一个绘制回调中使用不同的镜面光照参数来处理三角形图元。这里简单的使用一个shader参数就可以实现效果(当然可以尝试在顶点缓冲中添加不同的镜面强度参数然后在shader中获取来实现更复杂的镜面效果)。

    (lighting.vs:12)

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    out vec3 WorldPos0;
     
    void main()
    {
         gl_Position = gWVP * vec4(Position, 1.0 );
         TexCoord0 = TexCoord;
         Normal0 = (gWorld * vec4(Normal, 0.0 )).xyz;
         WorldPos0 = (gWorld * vec4(Position, 1.0 )).xyz;
    }

    上面顶点着色器多了最后一行代码,世界变换矩阵(之前用来变换法线的那个世界变换矩阵)这里用来将顶点的世界坐标传给片段着色器。这里有一个技术点是使用两个不同的矩阵来变换本地坐标提供的同一个顶点位置,并将结果独立的传递给片段着色器。经过完整的变换(world-view-projection变换)后结果传递给系统变量’gl_Position’,然后GPU负责将它变换到屏幕空间坐标系并用来进行实际的光栅化操作。局部变换到世界空间的结果传给了一个用户自定义的属性,这个属性在光栅化阶段被进行了简单的插值,所以片段着色器中激活的每一个像素都会提供它自己的世界空间位置坐标。这种技术很普遍也很有用。

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    (lighting.fs: 5 )
    in vec3 WorldPos0;
    .
    .
    .
    uniform vec3 gEyeWorldPos;
    uniform float gMatSpecularIntensity;
    uniform float gSpecularPower;
     
    void main()
    {
         vec4 AmbientColor = vec4(gDirectionalLight.Color * gDirectionalLight.AmbientIntensity, 1 .0f);
         vec3 LightDirection = -gDirectionalLight.Direction;
         vec3 Normal = normalize(Normal0);
     
         float DiffuseFactor = dot(Normal, LightDirection);
     
         vec4 DiffuseColor = vec4( 0 , 0 , 0 , 0 );
         vec4 SpecularColor = vec4( 0 , 0 , 0 , 0 );
     
         if (DiffuseFactor > 0 ) {
             DiffuseColor = vec4(gDirectionalLight.Color, 1 .0f) *
                 gDirectionalLight.DiffuseIntensity *
                 DiffuseFactor;
     
             vec3 VertexToEye = normalize(gEyeWorldPos - WorldPos0);
             vec3 LightReflect = normalize(reflect(gDirectionalLight.Direction, Normal));
             float SpecularFactor = dot(VertexToEye, LightReflect);
             if (SpecularFactor > 0 ) {
                 SpecularFactor = pow(SpecularFactor, gSpecularPower);
                 SpecularColor = vec4(gDirectionalLight.Color * gMatSpecularIntensity * SpecularFactor, 1 .0f);
             }
         }
     
         FragColor = texture2D(gSampler, TexCoord0.xy) * (AmbientColor + DiffuseColor + SpecularColor);
    }

    片段着色器中的变化是多了三个新的一致性变量,用来存储计算镜面光线的一些属性(像眼睛的位置、镜面光强度和镜面反射参数)。环境光颜色的计算和前面两篇教程中的计算一样。然后创建漫射光和镜面光颜色向量并初始化为0,之后只有当光线和物体表面的角度小于90度时颜色值才不为零,这个要通过漫射光参数来检查(和在漫射光教程中说的一样)。

    下一步要计算世界空间中从顶点位置到观察者位置的向量,这个通过观察者世界坐标和顶点的世界坐标相减计算得到,其中观察者的世界坐标是一个一致变量对于所有的像素点来说都一样。为了方便后面的点积操作这个向量要进行单位化。然后,使用内置的’reflect’函数就可以计算反射光向量了(当然也可以自行按照上面背景中介绍的手动计算)。’reflect’函数有两个参数:光线向量和物体表面法向量。注意这里使用的是最原始的射向物体表面的那个光源向量而不是用于漫射光参数计算的反向的光源向量(见上面图示)。然后计算镜面反射参数,也就是反射光和顶点到观察者那个向量的夹角余弦值(还是通过点积计算得到)。

    镜面反射效果只有在那个夹角小于90度时才看得到,所以我们要先检查点积的结果是否大于0。最后一个镜面颜色值是通过将光源颜色和材料的镜面反射强度以及材料镜面反射参数相乘计算得到。我们将镜面颜色值添加到环境光和漫射光颜色中来制造光颜色的整体效果。最后和从纹理中取样的颜色相乘得到最终的像素颜色。

    (tutorial19.cpp:134)

    ?
    1
    2
    3
    m_pEffect->SetEyeWorldPos(m_pGameCamera->GetPos());
    m_pEffect->SetMatSpecularIntensity( 1 .0f);
    m_pEffect->SetMatSpecularPower( 32 );

    镜面反射光颜色的使用很简单。在渲染循环我们得到了camera的位置(在世界空间中已经维护好了)并将它传给了LightingTechnique类。这里还设置了镜面反射强度和镜面参数。剩下的就由着色器来处理了。

    可以调整镜面反射的参数值以及光源的方向来看效果。当然为了找到可以看到镜面反射光效果的位置可能需要围着物体转一圈。


    展开全文
  • 结果表明,对称金属包覆结构可以大大增强反射光的干涉条纹中明、暗光线的对比度,同时光入射到对称金属包覆结构中的耦合效率可接近100%。这将有助于研究高对比度高反射率薄膜和基于对称金属包覆结构的传感器。
  • OpenGL学习之路17---- 镜面反射光

    千次阅读 2018-05-10 20:42:56
    代码放在github上 根据教程:ogldev一步步开始,记录学习历程 之前完成环境光和漫射光的学习。...镜面反射光是当光线以一定的角度照射到物体表面后,从法线的另一侧堆成的角度反射出去的光线 所...

    代码放在github上

    根据教程:ogldev一步步开始,记录学习历程

    之前完成环境光和漫射光的学习。环境光的计算只由光强来决定,场景中所有位置是同一亮度;漫射光的计算由光强和光的方向一同决定,相关博文如下:

    OpenGL学习之路15—-环境光

    OpenGL学习之路16—- 漫射光

    镜面反射光

    镜面反射光是当光线以一定的角度照射到物体表面后,从法线的另一侧堆成的角度反射出去的光线

    所以这个光线就与相机的位置有关,如果相机的位置正好在反射光线上则能感受到反射光线的照射,如果相机离反射光线有一定的角度则感受到反射光线的照射效果稍弱。

    观察下图:

    这里写图片描述

    • I:入射光
    • N:表面法向量
    • R:反射光,与I关于法线对称,方向相反
    • V:入射点到相机视点的向量,代表观察视线
    • α:反射光R和观察视线V的夹角

    由图可知当α(即反射光和观察视线的夹角)为0时,反射光的强度最大;随着α的角度不断增大,反射光的强度逐渐减小,当α为90°(即反射光和观察者视线垂直)时,感受不到反射光。

    引入α的余弦值,正好可以表示这种关系:
    这里写图片描述
    - 当α为0°时,α的余弦值为1,此时反射光强最大
    - 随着α值逐渐增大,余弦值逐渐减小
    - α为90°时,余弦值为0,继续增大值为负数则判定光强也为0

    计算夹角α:
    夹角α可以用,R(反射光)和V(观察视线)的点积来得到,关于点积的相关知识之前相机空间的博文中有讲到:
    OpenGL学习之路11—-相机空间

    计算观察视线V: 可以通过相机位置与入射点位置的差得到。(单位化)

    计算反射光R:

    这里写图片描述
    根据图中所示,我们可以引入一个向量W来计算反射光R:

    R = I + W

    而W的长度即为,两倍的向量I在单位法向量N的相反向量(-N)上的投影的长度,而这个投影长度可以使用点积得到,W的方向跟单位法向量相同,所以向量W:

    W = 2 * N * (-N · I)

    所以,反射光结合两个等式可以得到:

    R = I + 2 * N * (-N · I)
      = I - 2 * N * ( N · I)

    GLSL中提供了一个内部函数reflect(),用来做上述运算,即求一个向量经过法线堆成后的反射向量

    镜面反射的最终公式:
    这里写图片描述
    - 将光的颜色与物体表面颜色相乘
    - M:代表材料的镜面反射强度,这是由材料的物理特性决定的(比如木头就为0,金属的话这个值就大)
    - p:镜面发光参数,用来增强反射光区域边缘强度,这个值也是材料物体特性决定的

    镜面反射光的实现

    在之前平行光结构体的基础上,增加两个属性,分别代表我们的镜面反射强度M和镜面发光参数p:

    struct DirectionalLight
    {
        Vector3f Color;
        float AmbientIntensity;
        Vector3f Direction;
        float DiffuseIntensity;
    
        float SpecularIntensity; // 镜面反射强度
        float SpecularPower;     //镜面发光参数 
    };
    

    定义三个GLuint类型的全局变量,以便获得Uniform变量的Index索引:

    GLuint m_eyeWorldPosLocation;       //相机视点
    GLuint m_matSpecularIntensityLocation; // 镜面反射强度
    GLuint m_matSpecularPowerLocation;      //镜面发光参数

    获取Uniform变量的索引:

    m_eyeWorldPosLocation = glGetUniformLocation(ShaderProgram,"gEyeWorldPos");
    m_matSpecularIntensityLocation = glGetUniformLocation(ShaderProgram,"gDirectionalLight.SpecularIntensity");
    m_matSpecularPowerLocation = glGetUniformLocation(ShaderProgram, "gDirectionalLight.SpecularPower");

    在主函数中给镜面反射强度和镜面发光参数赋初值:

    m_directionalLight.SpecularIntensity = 1.0f;
    m_directionalLight.SpecularPower = 32.0f;

    在主渲染函数Render()中传递三个Uniform变量的值,分别是相机视点的位置,镜面反射强度和镜面发光参数:

    Vector3f EyeWorldPos;
    CopyVector3(EyeWorldPos, pGameCamera->GetPos());
    glUniform3f(m_eyeWorldPosLocation, EyeWorldPos[0], EyeWorldPos[1], EyeWorldPos[2]);
    glUniform1f(m_matSpecularIntensityLocation, m_directionalLight.SpecularIntensity);
    glUniform1f(m_matSpecularPowerLocation, m_directionalLight.SpecularPower);

    在顶点着色器中计算每个像素的世界坐标位置并作为输出变量传递到片元着色器中,shader.vs:

    #version 330
    
    layout (location=0) in vec3 Position;
    layout (location=1) in vec2 TexCoord;
    layout (location=2) in vec3 Normal;
    
    uniform mat4 gWVP;
    uniform mat4 gWorld;
    
    out vec2 TexCoord0;
    out vec3 Normal0;
    out vec3 WorldPos0;   
    
    void main()
    {
        gl_Position = gWVP*vec4(Position,1.0);
        TexCoord0 = TexCoord;
        Normal0= (gWorld * vec4(Normal,0.0)).xyz;
        WorldPos0 = (gWorld * vec4(Position, 1.0)).xyz;  
    }

    main()函数中的最后一句即为计算,每个像素点的世界坐标位置

    最后在片元着色器中计算最终的颜色。shader.fs:

    #version 330
    
    in vec2 TexCoord0;
    in vec3 Normal0;
    in vec3 WorldPos0;
    
    out vec4 FragColor;
    
    struct DirectionalLight
    {
        vec3 Color;
        float AmbientIntensity;
        float DiffuseIntensity;
        vec3 Direction;
        float SpecularIntensity; // 镜面反射强度
        float SpecularPower;     //镜面发光参数 
    };
    
    uniform DirectionalLight gDirectionalLight;
    uniform sampler2D gSampler;
    uniform vec3 gEyeWorldPos;                                                          
    
    
    void main()
    {
        vec4 AmbientColor = vec4(gDirectionalLight.Color * gDirectionalLight.AmbientIntensity, 1.0f);
        vec3 LightDirection = -gDirectionalLight.Direction;
        vec3 Normal = normalize(Normal0);   
    
        float DiffuseFactor = dot(Normal, LightDirection);   
    
        vec4 DiffuseColor  = vec4(0, 0, 0, 0);
        vec4 SpecularColor = vec4(0, 0, 0, 0);            
    
        if (DiffuseFactor > 0) {           
            DiffuseColor = vec4(gDirectionalLight.Color * gDirectionalLight.DiffuseIntensity * DiffuseFactor, 1.0f);
    
            vec3 VertexToEye = normalize(gEyeWorldPos - WorldPos0); 
            vec3 LightReflect = normalize(reflect(gDirectionalLight.Direction, Normal));
            float SpecularFactor = dot(VertexToEye, LightReflect);                      
            if (SpecularFactor > 0) {
                SpecularFactor = pow(SpecularFactor, gDirectionalLight.SpecularPower);
                SpecularColor = vec4(gDirectionalLight.Color * gDirectionalLight.SpecularIntensity * SpecularFactor, 1.0f);
            }                                                                           
        }                   
        FragColor = texture2D(gSampler, TexCoord0.xy) * (AmbientColor + DiffuseColor + SpecularColor);
    }
    • 环境光(AmbientColor)计算没有发生变化,先计算出环境光颜色
    • 再对入射光线取反,这里原因在上一节有讲,因为比如垂直入射到物体表面,入射角α应该为0°,然而法向量竖直向上是180°所以要取反一下
    • 对每个像素的顶点法线(Normal0)单位化,因为经过顶点着色器计算后不是一定是单位向量
    • 漫射光计算也跟上一节一样,计算出入射角与法线的角度余弦值(DiffuseFactor),通过入射光向量和顶点法向量的点积得到
    • 如果入射角小于90°即(余弦值DiffuseFactor大于0),则计算出漫射光颜色(DiffuseColor),即光的颜色乘慢射光强乘入射角余弦值; 入射角如果大于90°则光线没有影响即光颜色为(0,0,0,0)
    • 按照前面推理的镜面反射光计算方法来计算镜面反射光:

    得到观察视线的单位向量:相机位置-像素位置,再单位化:

    vec3 VertexToEye = normalize(gEyeWorldPos - WorldPos0); 

    得到入射光经过平面得到的反射光向量:使用GLSL内置函数得到入射光与法向量对应的反射光向量,再单位化:

    vec3 LightReflect = normalize(reflect(gDirectionalLight.Direction, Normal));

    得到观察视线与反射光之间的夹角:点积后得到:

    float SpecularFactor = dot(VertexToEye, LightReflect); 

    如果夹角小于90°,则正面镜面反射光有效,此时根据上面的镜面反射光计算公式来得出镜面反射光颜色:

    if (SpecularFactor > 0) {
        SpecularFactor = pow(SpecularFactor, gDirectionalLight.SpecularPower);
        SpecularColor = vec4(gDirectionalLight.Color * gDirectionalLight.SpecularIntensity * SpecularFactor, 1.0f);
    }  
    • 最后根据纹理颜色,环境光颜色、漫射光颜色和镜面反射光颜色共同得出像素颜色:
    FragColor = texture2D(gSampler, TexCoord0.xy) * (AmbientColor + DiffuseColor + SpecularColor);

    运行结果

    在之前调环境光和漫射光的基础上,增加了调镜面反射强度和镜面发光参数的按键,来观察变化

    光从(1,0,0)入射时:
    这里写图片描述

    光从(1,1,0)入射时:
    这里写图片描述

    并且也可以通过调整镜面发光参数可以看出来(自行实验),镜面发光参数越大,反射的面积集中,镜面发光参数越小,反射的光越发散

    展开全文
  • 文章目录Phong算法中影响光照的三个因素环境对其他光线的影响漫反射对光线的影响镜面反射对光线的影响 Phong着色算法将模拟对模型中每个顶点的影响。所以这个算法没法考虑阴影,它只会计算应用于每个顶点的光线...

    Phong着色算法将模拟光对模型中每个顶点的影响。所以这个算法没法考虑阴影,它只会计算应用于每个顶点的光线,而不考虑顶点是否位于阻挡光线的物体后面。但是,正因为如此,这是一种非常简单快速的算法,可以提供非常好的效果。

    关于光的种类可以参考这篇文章OpenGL的环境光、点光源、聚光灯、方向光、材质的定义,本文主要介绍点光源、聚光灯、方向光在Phong算法下物体的效果。

    Phong算法中影响光照的三个因素

    • 环境光(Ambient):可以理解为现实中的白天的室内,白天在室内我们能看的见物体,但是并没有感知光线的方向,其实是因为太阳离我们太远了,导致我们周围的光线强度都是一样的。
    • 漫反射(Diffuse):面向光源的表面更亮。
    • 镜面反射(Specular):模拟光在抛光或金属表面的反射

    其实最终我们就是要计算出一个影响颜色的因子,在执行片段着色器程序时用这个变量fragColor去乘以该因子,进而根据接收的光线将颜色设置得更亮或更暗。将场景中对其他光的影响因素环境光、漫反射、镜面反射分别叫做A、D、S,则计算那个影响颜色的因子可以用下面公式来表示。

    • 如果模型没有纹理,将按照下面这个公式去算:
      在这里插入图片描述
    • 有纹理,将按照下面这个公式去算:
      在这里插入图片描述

    环境光(Ambient)对光线的影响

    它只是一个常数因素,可以使我们所有的物体更亮或更暗。环境光是最容易计算一种影响因素。我们只需要传递一种颜色,用它乘以模型的基色,它只是调制基色。所以我们只需要一个矢量来调制环境光强度和颜色。

    漫反射(Diffuse)对光的影响

    以点光源为例:假设有一个光源照在一个物体上,面向光源的一面整体会比背向光源的一面更亮。

    在这里插入图片描述

    对于漫反射的计算,首先在上图中的物体上取几个顶点位置P1、P2、P3,相应的顶点法向量为N1、N2、N3。顶点法向量是垂直于每个点的切平面的矢量。如下:

    在这里插入图片描述

    在上图中可以很明显的看出来,P1位置一定比P2更亮,P3基本不会受到该光源的影响。而P1位置比P2更亮是因为,P1受到的光照是从该顶点的正上方照射过来的,而P2受到的光线是比正上方稍微偏了一些。所以我们在计算每个顶点的漫反射影响因子时,顶点的法向量与该点受到光线的夹角是影响明暗的一个因素。

    现在我们列出计算漫反射的已知参数:

    • vPos: 顶点坐标
    • lPos:灯的坐标
    • intensity:光线的强度 (范围是 0 to 1).
    • lColour:光的颜色
    • normal:顶点法向量

    在这里插入图片描述

    1、每个顶点受到的光照方向
    在这里插入图片描述

    2、每个顶点受到的光线强度:这里用顶点的法向量点乘光的方向,作为光线强度的影响因子,在两个向量夹角在0-90度之间时,夹角越大,点乘值越大。
    在这里插入图片描述
    3、每个顶点的颜色如下:diffuseColour指的是,如果没有纹理,该物体在漫反射下的颜色,可以理解为定义的物体的颜色。

    在这里插入图片描述

    如果是放方向光(DirectionalLight),那么直略过第一步的计算灯光方向,其余过程都是一致的。

    镜面反射(Specular)对光的影响

    当光线照射到表面时,它的某些部分被吸收而另一部分被反射,反射就是光线从物体上反射回来。镜面反射如下:

    在这里插入图片描述

    将空间中的观察点,比作相机(Camera)对于镜面反射,最重要的是要注意,只有当相机处于适当的位置时,反射光才会可见。例如,如果相机位于反射光发射的区域,光线才会可见。是否可见如下:

    在这里插入图片描述

    计算镜面反射光的流程:

    1、首先求与入射光方向相反的向量
    在这里插入图片描述

    2、利用着色器的内置函数来计算反射光向量reflect(x,y)函数的是求x向量关于y向量的对称向量。
    在这里插入图片描述

    3、计算镜面反射光的强度cameraDirection是相机的方向向量。
    在这里插入图片描述

    在这里插入图片描述

    4、当反射光直面相机的方向时,需要将反射光的强度加强。
    在这里插入图片描述

    5、最终的镜面反射光如下:specularColour指的是,如果没有纹理,该物体在镜面反射下的颜色,可以理解为定义的物体的颜色。
    在这里插入图片描述

    衰减(Attenuation)

    上面已经模拟了在环境光下,漫反射和镜面反射对点光源的影响。但是到此位置光模型仍然不完整,物体反射的光与光的距离是有关的,我们需要模拟光的衰减。
    在这里插入图片描述
    上面公式中dist表示光源到顶点的距离,atConstantatLinearatExponent表示三个调整参数,其实就将我们可以调整的参数范围变得更大更详细了。

    注意:只有点光源、聚光灯才需要考虑衰减。方向光是不用考虑衰减的。

    展开全文
  • 蛋白质表面相互作用对药物释放、生物传感器、亲和色谱和离子色谱以及仿生材料在生物环境中均起到关 键作用。...这些研究有助于进一步加强对蛋白质表面相互作用的理解。近年来全内反射技术在蛋白质领域的应用,为其在
  • 使用Ta2O5 / SiO2混合DBR反射增强近紫外LED的输出
  • 蓝绿LED通信被认为是解决水下近距离高速无线数据传输的有效手段...这表明基于TIR透镜二次配的方法,可有效减小发射机出射角,降低链路损耗,增强通信系统的传输能力。这为提升水下LED通信的传输性能提供了新的技术思路。
  • OpenGL着色器程序解析--镜面反射光

    千次阅读 2018-06-20 15:38:57
    背景我们在计算环境的时候,的强度是唯一的影响因素。然后处理漫射的时候公式中加入了的方向参数。镜面反射包含了上面所有的综合因素并且添加了一个新的元素:观察者的位置。镜面反射时光以一定角度照射到...

    转载自:https://blog.csdn.net/cordova/article/details/52996876

    背景

    我们在计算环境光的时候,光的强度是唯一的影响因素。然后处理漫射光的时候公式中加入了光的方向参数。镜面反射包含了上面所有的综合因素并且添加了一个新的元素:观察者的位置。镜面反射时光以一定角度照射到物体表面,同时会在法线的另一侧对称的角度上反射出去,如果观察者刚好在反射光线的路径上那么就会看到格外强烈的光线。

    镜面反射最终的结果是物体在从某个角度看上去会十分明亮,而移动开后这个光亮又会消失。现实中好的镜面反射的例子是金属物体,这些物体有时候看上去由于太亮了导致看不到他本来的颜色而是直接照向你眼睛的白色的亮光。但这种属性在其他的一些材料上是没有的(比如:木头)。很多东西根本不会发光,不管光源从什么角度照射以及观察者在什么位置。所以,镜面反射光的存在更取决于反射物体的材料性质而不是光源本身。

    现在看如何将观察者的位置加入到镜面反射光的计算当中,看下图:

    image description

    要注意五个因素:

    ‘I’ 是入射光

    ‘N’ 是表面法线

    ‘R’ 反射光,和入射光’I’关于法线对称,但方向相反

    ‘V’ 是从入射光和反射光交点处(入射点)到观察者眼睛的向量,表示观察者视线

    ‘α’ 反射光’R’和观察者视线’V’的夹角

    我们将使用夹角’α’来对镜面反射光现象进行建模。有一点可以看出当观察者视线和反射光重合时(夹角为0),反射光的强度最大。观察者慢慢从反射光’R’移开时,夹角慢慢变大,而我们希望随着角度增大反射光要慢慢衰弱。明显,这里又要使用差积运算来计算夹角’α’的余弦值了,这个值将作为计算镜面反射光公式的反射参数。当’α’为0时余弦值为1,这是我们反射参数的最大值。随着夹角’α’增大余弦值慢慢减小,直到夹角达到90度时就彻底没有镜面反射的效果了。当然,夹角大于90度时余弦值为负,也没有任何反射效果,也就是观察者不在反射光的路径范围内。

    我们要用到’R’和’V’来计算夹角’α’。’V’可以通过世界坐标系中观察者位置和光的入射点位置的差计算得到。camera已经在世界空间进行维护了,我们只需要将它的位置传给shader着色器。另外上面的图是经过简化了的模型,光在物体表面只有一个入射点(事实上不是,这里只是为了好分析)。事实上,整个三角形都被点亮了(假设它面向光源),因此我们要计算每一个像素的镜面反射效果(和漫反射光的计算一样)。我们必须要知道每个像素在世界空间的位置,这个不难:可以将顶点变换到世界空间,让光栅器对像素的世界空间位置进行插值并将结果传给片段着色器。事实上,这个和之前教程中对法线的处理操作是一样的。

    最后是要使用’I’向量(由应用传给shader)来计算反射光线’R’。如下图:

    image description

    首先要强调向量没有起点的概念,所有方向相同且长度相同的向量都是同一个向量。因此,图中将入射光向量’I’复制到表面下面位置向量本身是不变的。目标是求向量’R’,根据向量的加法,’R’等于’I’+’V’。’I’是已知的,所以我们要求’V’。注意法线’N’的反向向量为’-N’,计算’I’和’-N’的点积可以得到’I’在’-N’上的投影,这也是’V’的模长度的一半。另外’V’和’N’的方向是相同的,所以只要用计算的那个投影长度乘以单位向量’N’再乘以2就是向量’V’了。用公式简单表示如下:

    image

    明白这个数学公式后可以说一个相关的知识点:GLSL提供了一个叫做’reflect’的内部函数就是做的上面这个计算。可以看下面这个函数在shader中的用法。这里得出计算镜面反射的最终公式:

    image description

    开始先是将光的颜色和物体表面的颜色相乘,这个和在计算环境光以及漫反射光时一样。得到的结果再和材料的镜面反射强度参数(’M’)相乘。如果材料没有反射性能,比如木头,那么镜面反射参数就为0,整个公式的结果也就为0了,而像金属这种发光材料镜面反射能力就会很强。之后再乘以光线和观察者视线夹角的余弦值,这也是最后一个调整镜面反射光强度的参数(‘镜面参数’或者叫做‘发光参数’)。镜面参数是用来增强加剧反射光区域边缘的强度的。下面的图片展示了镜面参数为1时的效果:

    image description

    下面的镜面参数为32:

    image description

    镜面反射能力也被认为是材料的一种属性,因此不同的物体会有不同的镜面反射能力值。

    源代码详解

    (lighting_technique.h:32)

    class LightingTechnique : public Technique
    {
    public:
    ...
        void SetEyeWorldPos(const Vector3f& EyeWorldPos);
        void SetMatSpecularIntensity(float Intensity);
        void SetMatSpecularPower(float Power);
    
    private:
    ...
        GLuint m_eyeWorldPosLocation;
        GLuint m_matSpecularIntensityLocation;
        GLuint m_matSpecularPowerLocation;
    }

    LightingTechnique类中有了三个新属性:眼睛(观察者)的位置、镜面反射强度和材料的镜面参数。这三个参数都是独立于光线本身的,因为当同一束光照到不同的材料上(比如:木头和金属)时会有不同的反射发光效果。目前对材料属性的的使用模型还是很局限的,同一个绘制回调的所有三角形会得到这些属性的一样的值。如果同一个模型的不同部分的三角形图元是不同的材料,这样就不合理了。在后面的教程中讲关于mesh网格的加载时我们会在一个模块中产生不同的镜面参数值并作为顶点缓冲器的一部分(而不是shader的一个参数),这样我们就可以在同一个绘制回调中使用不同的镜面光照参数来处理三角形图元。这里简单的使用一个shader参数就可以实现效果(当然可以尝试在顶点缓冲中添加不同的镜面强度参数然后在shader中获取来实现更复杂的镜面效果)。

    (lighting.vs:12)

    out vec3 WorldPos0;
    
    void main()
    {
        gl_Position = gWVP * vec4(Position, 1.0);
        TexCoord0 = TexCoord;
        Normal0 = (gWorld * vec4(Normal, 0.0)).xyz;
        WorldPos0 = (gWorld * vec4(Position, 1.0)).xyz;
    }
    上面顶点着色器多了最后一行代码,世界变换矩阵(之前用来变换法线的那个世界变换矩阵)这里用来将顶点的世界坐标传给片段着色器。这里有一个技术点是使用两个不同的矩阵来变换本地坐标提供的同一个顶点位置,并将结果独立的传递给片段着色器。经过完整的变换(world-view-projection变换)后结果传递给系统变量’gl_Position’,然后GPU负责将它变换到屏幕空间坐标系并用来进行实际的光栅化操作。局部变换到世界空间的结果传给了一个用户自定义的属性,这个属性在光栅化阶段被进行了简单的插值,所以片段着色器中激活的每一个像素都会提供它自己的世界空间位置坐标。这种技术很普遍也很有用。
    (lighting.fs:5)
    in vec3 WorldPos0;
    .
    .
    .
    uniform vec3 gEyeWorldPos;
    uniform float gMatSpecularIntensity;
    uniform float gSpecularPower;
    
    void main()
    {
        vec4 AmbientColor = vec4(gDirectionalLight.Color * gDirectionalLight.AmbientIntensity, 1.0f);
        vec3 LightDirection = -gDirectionalLight.Direction;
        vec3 Normal = normalize(Normal0);
    
        float DiffuseFactor = dot(Normal, LightDirection);
    
        vec4 DiffuseColor = vec4(0, 0, 0, 0);
        vec4 SpecularColor = vec4(0, 0, 0, 0);
    
        if (DiffuseFactor > 0) {
            DiffuseColor = vec4(gDirectionalLight.Color, 1.0f) *
                gDirectionalLight.DiffuseIntensity *
                DiffuseFactor;
    
            vec3 VertexToEye = normalize(gEyeWorldPos - WorldPos0);
            vec3 LightReflect = normalize(reflect(gDirectionalLight.Direction, Normal));
            float SpecularFactor = dot(VertexToEye, LightReflect);
            if (SpecularFactor > 0) {
                SpecularFactor = pow(SpecularFactor, gSpecularPower);
                SpecularColor = vec4(gDirectionalLight.Color * gMatSpecularIntensity * SpecularFactor, 1.0f);
            }
        }
    
        FragColor = texture2D(gSampler, TexCoord0.xy) * (AmbientColor + DiffuseColor + SpecularColor);
    }

    片段着色器中的变化是多了三个新的一致性变量,用来存储计算镜面光线的一些属性(像眼睛的位置、镜面光强度和镜面反射参数)。环境光颜色的计算和前面两篇教程中的计算一样。然后创建漫射光和镜面光颜色向量并初始化为0,之后只有当光线和物体表面的角度小于90度时颜色值才不为零,这个要通过漫射光参数来检查(和在漫射光教程中说的一样)。

    下一步要计算世界空间中从顶点位置到观察者位置的向量,这个通过观察者世界坐标和顶点的世界坐标相减计算得到,其中观察者的世界坐标是一个一致变量对于所有的像素点来说都一样。为了方便后面的点积操作这个向量要进行单位化。然后,使用内置的’reflect’函数就可以计算反射光向量了(当然也可以自行按照上面背景中介绍的手动计算)。’reflect’函数有两个参数:光线向量和物体表面法向量。注意这里使用的是最原始的射向物体表面的那个光源向量而不是用于漫射光参数计算的反向的光源向量(见上面图示)。然后计算镜面反射参数,也就是反射光和顶点到观察者那个向量的夹角余弦值(还是通过点积计算得到)。

    镜面反射效果只有在那个夹角小于90度时才看得到,所以我们要先检查点积的结果是否大于0。最后一个镜面颜色值是通过将光源颜色和材料的镜面反射强度以及材料镜面反射参数相乘计算得到。我们将镜面颜色值添加到环境光和漫射光颜色中来制造光颜色的整体效果。最后和从纹理中取样的颜色相乘得到最终的像素颜色。

    (tutorial19.cpp:134)

    m_pEffect->SetEyeWorldPos(m_pGameCamera->GetPos());
    m_pEffect->SetMatSpecularIntensity(1.0f);
    m_pEffect->SetMatSpecularPower(32);

    镜面反射光颜色的使用很简单。在渲染循环我们得到了camera的位置(在世界空间中已经维护好了)并将它传给了LightingTechnique类。这里还设置了镜面反射强度和镜面参数。剩下的就由着色器来处理了。

    可以调整镜面反射的参数值以及光源的方向来看效果。当然为了找到可以看到镜面反射光效果的位置可能需要围着物体转一圈。




    展开全文
  • 具有长测量范围的数字增强频域反射
  • 为了对加强筋宽度进行在役、快速、非接触、...将反射横波幅值作为特征信号对304不锈钢板上的加强筋进行激光超声C扫描测量,结果表明,从图像中获取的加强筋宽度和实际宽度的绝对误差小于0.05 mm,满足工程检测的误差要求。
  • 设计了一种基于弱光纤布拉格光栅阵列的增强相位敏感时域反射仪(-OTDR)振动传感系统,以反射率较大的弱光纤光栅反射信号代替-OTDR中的瑞利散射信号,利用相邻弱光纤光栅反射信号间干涉信号的强度变化来判断光纤...
  • 体内声腔的肺部感应增强了体内反射模式的声显微镜。
  • 教程19镜面反射光原文: http://ogldev.atspace.co.uk/www/tutorial19/tutorial19.htmlCSDN完整版专栏: http://blog.csdn.net/column/details/13062.html背景我们在计算环境光的时候,光的强度是唯一的影响因素。...
  • OpenGL教程翻译 第十八课 漫反射光

    千次阅读 2015-09-17 12:44:08
    第十八课 漫反射光背景环境光和漫反射光的主要不同是,漫反射光的计算需要依靠光线方向而环境光完全忽略了它!当只有环境光时整个场景被均等照亮,漫反射光会使物体面对光的部分比背对光的部分更加明亮。此外漫反射...
  • 叠层背反射结构太阳电池对300~1200 nm全波段具有最优的吸收增强效果,相对金属铝背反射结构吸收平均增加了32%,优于单独使用金属光栅或者光子晶体的效果。由于金属光栅和光子晶体良好的反射特性,透射反射回...
  • 为了解高渗溶液渗透特性对生物组织的光学透明进程的影响,探索透明剂的安全有效浓度,用近红外反射光谱和相干断层成像(OCT)研究了两种透明剂丙三醇(甘油)和二甲亚砜(DMSO)以及二者的混合溶液[体积分数为80%的...
  • 实验证明该异型布拉格反射镜在730~1155 nm的光谱范围内反射率达到90%,在750~1110 nm波长范围内的反射率高达95%,从而具有显著提高太阳能电池的宽谱吸收效率的潜力,可以对1000~1155 nm范围内的红外进行有效反射,...
  • 为进一步增强光线反射优化(OIO)算法的全局寻优能力,基于House-Holder变换和混合多光源策略提出混合光线反射优化 (SOIO)算法。算例分析表明所提方法可有效求解最近电压稳定临界点,计算效率高且全局搜索能力强。
  • 激光超声检测中增强反射波算法的研究,杨玮萍,郑宾,在激光超声无损检测中,当入射的超声波遇到结构损伤时,部分入射波会被反射。对反射波信号的分析处理可以实现对损伤的检测与评估
  • 在混合机械系统中通过真空感应的发射器-反射镜耦合增强稳态纠缠
  • 六方氮化硼纳米片结合了抗反射二氧化硅涂层,具有增强的激光诱导损伤阈值
  • 在多Kong硅布拉格反射器中通过金纳米颗粒沉积增强R6G荧光
  • 分析了内含磁致旋介质的旋光反射腔的偏光特性, 理论预言这种旋光反射腔具有旋光增强效应, 在此基础上提出了微量样品的旋光增强检测方法和器件设计原理。研究结果表明, 该方法可以在小光程限制条件下显著提高磁旋...
  • 如果用520 nm单色光源来测量反射率和光谱响应,则“超Ⅱ代像增强器”的光电阴极的厚度应在120 nm左右,即峰值RM3。出现后,S/Smax约为60%时,根据(RM1,RM)和(RM,RM2)确定n、k值以及光电流在光谱响应峰值前的稳定上升和...
  • 使用TiO2 / SiO2-Al全向反射增强从Si(111)衬底转移到电镀Cu基座上的GaN基发光二极管

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 12,179
精华内容 4,871
关键字:

反射光加强