zoukankan      html  css  js  c++  java
  • opengl 教程(20) 点光源

    原帖地址: http://ogldev.atspace.co.uk/www/tutorial20/tutorial20.html

          前面的教程中,我们在方向光的前提下,研究了基本的光照模型(环境光,漫反射光,高光)。方向光没有起点,所有光线都是沿着一个方向,它的强度不会随着距离的增加有任何变化。本篇教程中,我们开始研究点光源,点光源是起始于一个点,向四面照射,会随着传输距离增加而衰减,所以在点光源属性中,我们会增加一个光源位置。

    通常点光源衰减程度离物体距离的平方成反,如下面的公式:

    inverse_square_law

          但在距离比较小的时候,上面的公式在3D图形学中,效果并不好,所以我们计算点光源衰减系数时候,常使用下面的公式:它包括3个因子,常量因子,线性因子和二次因子。

    attenuation

    下面我们总结一下计算点光源时需要的步骤:

    1. 环境光的计算和方向光一样
    2. 在世界坐标系中,计算点(像素)到光源的方向,做为光源的方向向量。
    3. 计算像素到光源的距离,用来计算衰减因子。
    4. 把环境光、漫反射光和高光加起来,然后乘以衰减因子。

     

    lighting_technique.h

    struct BaseLight
    {
    Vector3f Color;
    float AmbientIntensity;
    float DiffuseIntensity;
    };
    .
    .
    .
    struct PointLight : public BaseLight
    {
    Vector3f Position;
    struct
    {
    float Constant;
    float Linear;
    float Exp;
    } Attenuation;
    }

          建立一个BaseLight类,抽象出光源的共有属性,然后派生出点光源和方向光源,它们都有自己特有的属性,比如点光源的位置,衰减系数,方向光的方向等等。

    lighting_technique.h

    void SetPointLights(unsigned int NumLights, const PointLight* pLights);

    除了演示点光源,本教程中还要实施多光源,包括一个方向光和多个电光源。

    struct {
    GLuint Color;
    GLuint AmbientIntensity;
    GLuint DiffuseIntensity;
    GLuint Position;
    struct
    {
    GLuint Constant;
    GLuint Linear;
    GLuint Exp;
    } Atten;
    } m_pointLightsLocation[MAX_POINT_LIGHTS];

    我们使用结构数组来实现多个点光源,MAX_POINT_LIGHTS是个常量值,指定光源的数目,缺省值是2。

    lighting_technique.cpp

    vec4 CalcLightInternal(BaseLight Light, vec3 LightDirection, vec3 Normal)
    {
    vec4 AmbientColor = vec4(Light.Color, 1.0f) * Light.AmbientIntensity;
    float DiffuseFactor = dot(Normal, -LightDirection);
    vec4 DiffuseColor = vec4(0, 0, 0, 0);
    vec4 SpecularColor = vec4(0, 0, 0, 0);
    if (DiffuseFactor > 0) {
    DiffuseColor = vec4(Light.Color, 1.0f) * Light.DiffuseIntensity * DiffuseFactor;
    vec3 VertexToEye = normalize(gEyeWorldPos - WorldPos0);
    vec3 LightReflect = normalize(reflect(LightDirection, Normal));
    float SpecularFactor = dot(VertexToEye, LightReflect);
    SpecularFactor = pow(SpecularFactor, gSpecularPower);
    if (SpecularFactor > 0) {
    SpecularColor = vec4(Light.Color, 1.0f) *
    gMatSpecularIntensity * SpecularFactor;
    }
    }
    return (AmbientColor + DiffuseColor + SpecularColor);
    }

    上面是计算点光源的通用函数,计算点光源和方向光时候,我们都可以调用该函数来实现。

    vec4 CalcDirectionalLight(vec3 Normal)
    {
    return CalcLightInternal(gDirectionalLight.Base, gDirectionalLight.Direction, Normal);
    }

    上面是调用该函数实现方向光计算。

    vec4 CalcPointLight(int Index, vec3 Normal)
    {
    vec3 LightDirection = WorldPos0 - gPointLights[Index].Position;
    float Distance = length(LightDirection);
    LightDirection = normalize(LightDirection);
    vec4 Color = CalcLightInternal(gPointLights[Index].Base, LightDirection, Normal);
    float Attenuation = gPointLights[Index].Atten.Constant +
    gPointLights[Index].Atten.Linear * Distance +
    gPointLights[Index].Atten.Exp * Distance * Distance;
    return Color / Attenuation;
    }

    上面是调用该函数实现点光源计算。

    void main()
    {
    vec3 Normal = normalize(Normal0);
    vec4 TotalLight = CalcDirectionalLight(Normal);
    for (int i = 0 ; i < gNumPointLights ; i++) {
    TotalLight += CalcPointLight(i, Normal);
    }
    FragColor = texture2D(gSampler, TexCoord0.xy) * TotalLight;
    }

    最终输出最终像素颜色时候,我们把所有光源的效果加起来,并用纹理颜色进行调制。

    void LightingTechnique::SetPointLights(unsigned int NumLights, const PointLight* pLights) {
    glUniform1i(m_numPointLightsLocation, NumLights);
    for (unsigned int i = 0 ; i < NumLights ; i++) {
    glUniform3f(m_pointLightsLocation[i].Color, pLights[i].Color.x, pLights[i].Color.y, pLights[i].Color.z);
    glUniform1f(m_pointLightsLocation[i].AmbientIntensity, pLights[i].AmbientIntensity);
    glUniform1f(m_pointLightsLocation[i].DiffuseIntensity, pLights[i].DiffuseIntensity);
    glUniform3f(m_pointLightsLocation[i].Position, pLights[i].Position.x, pLights[i].Position.y, pLights[i].Position.z);
    glUniform1f(m_pointLightsLocation[i].Atten.Constant, pLights[i].Attenuation.Constant);
    glUniform1f(m_pointLightsLocation[i].Atten.Linear, pLights[i].Attenuation.Linear);
    glUniform1f(m_pointLightsLocation[i].Atten.Exp, pLights[i].Attenuation.Exp);
    }
    }

    上面是给各个uniform变量赋值。

    程序执行后界面如下,我们使用了2个点光源:

    clipboard

  • 相关阅读:
    Atitit.Java exe bat  作为windows系统服务程序运行
    Atitit. Object-c语言 的新的特性  attilax总结
    Atitit. Object-c语言 的新的特性  attilax总结
    Atitit。Time base gc 垃圾 资源 收集的原理与设计
    Atitit。Time base gc 垃圾 资源 收集的原理与设计
    Atitit.go语言golang语言的新的特性  attilax总结
    Atitit.go语言golang语言的新的特性  attilax总结
    Atitit.pdf 预览 转换html attilax总结
    Atitit.pdf 预览 转换html attilax总结
    Atitit.office word  excel  ppt pdf 的web在线预览方案与html转换方案 attilax 总结
  • 原文地址:https://www.cnblogs.com/mikewolf2002/p/2877507.html
Copyright © 2011-2022 走看看