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

  • 相关阅读:
    linux中RabbitMQ安装教程
    linux中的文件权限chmod
    ceph架构简介
    利用双重检查锁定和CAS算法:解决并发下数据库的一致性问题
    对接第三方服务引起的小思考-回调和Sign算法
    <<Java并发编程的艺术>>-阅读笔记和思维导图
    SpringBoot2+Netty打造通俗简版RPC通信框架(升级版)
    SpringBoot2+Netty打造通俗简版RPC通信框架
    [安全] Kali Linux (debian)系统使用记录
    [安全] nmap工具的使用
  • 原文地址:https://www.cnblogs.com/mikewolf2002/p/2877507.html
Copyright © 2011-2022 走看看