• 《Qt-OpenGL系列编程》课程学习记录(10):冯氏光照模型


    冯氏光照模型的3个主要结构

    环境光(Ambient Lighting)

    用于综合那些细微的不易于处理的“小光照”,将它们的影响合计为一个环境光照常量,因此物体在没有主光源的情况下也存在一些颜色。

    漫反射光(Diffuse Lighting)

    模拟物体对光源的漫反射

    物体的某一部分越是正对着(越接近90°)光源,就越亮;越是在侧面(越是解决0°)就越暗。

    镜面光照(Specular Lighting)

    模拟物体对光源的镜面反射。镜面光照的颜色相比于物体的颜色会更倾向于光的颜色。

    反射光的计算原理

    在0~90度之间的位置的光照亮度在两者之间。

    有一种数学计算能模拟这种情况,即向量的点乘:光线向量和像素点的法线向量做点乘运算

    镜面反射的计算原理

    只有眼睛在和入射角接近的角度才能看到反射光线(比如现实中看镜子里的物体时要移动位置)。 

    镜面反射光 = 反射光的向量R * 眼睛位置的向量E。

    代码实现

    光源的着色器和上一篇一样:

    1. //顶点着色器light.vert
    2. #version 450 core
    3. layout (location = 0) in vec3 aPos;
    4. uniform mat4 model;
    5. uniform mat4 view;
    6. uniform mat4 projection;
    7. void main()
    8. {
    9. gl_Position = projection * view * model * vec4(aPos, 1.0);
    10. }
    1. //片段着色器 light.frag
    2. #version 450 core
    3. out vec4 FragColor;
    4. uniform vec3 lightColor;
    5. void main()
    6. {
    7. FragColor = vec4(lightColor, 1.0);
    8. }

    被照射物体的着色器:

    1. //顶点着色器 shapes.vert
    2. #version 450 core
    3. layout (location = 0) in vec3 aPos;//顶点坐标
    4. layout (location = 1) in vec3 aNormal;//法线数据
    5. out vec3 Normal;
    6. out vec3 FragPos;
    7. uniform mat4 model;
    8. uniform mat4 view;
    9. uniform mat4 projection;
    10. void main()
    11. {
    12. Normal = mat3(transpose(inverse(model))) * aNormal;//法线矩阵的公式 处理后得到法向量
    13. FragPos = vec3(model * vec4(aPos,1.0));
    14. gl_Position = projection * view * model * vec4(aPos, 1.0);
    15. }
    1. //片段着色器 shapes.frag
    2. #version 450 core
    3. out vec4 FragColor;
    4. in vec3 Normal;//法向量
    5. in vec3 FragPos;//顶点
    6. uniform vec3 objectColor;
    7. uniform vec3 lightColor;
    8. uniform vec3 lightPos;//光源位置
    9. uniform vec3 viewPos;//摄像机/眼睛位置
    10. void main()
    11. {
    12. // 环境光
    13. float ambientStrength = 0.1;//环境光强度系数
    14. vec3 ambient = ambientStrength * lightColor;//环境光(物体反射的光源的颜色)
    15. // 漫反射
    16. vec3 norm = normalize(Normal);//法向量归一化
    17. vec3 lightDir = normalize(lightPos - FragPos);//顶点到光源的向量
    18. float diff = max(dot(norm, lightDir), 0.0);//法向量 与 顶点到光源的向量 进行点乘
    19. vec3 diffuse = diff * lightColor;//漫反射光
    20. // 镜面反射
    21. float specularStrength = 0.5;//镜面反射系数
    22. vec3 viewDir = normalize(viewPos - FragPos);//摄像机位置 - 顶点位置
    23. vec3 reflectDir = reflect(-lightDir, norm);//光的折射向量
    24. float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);//摄像机 与 反射向量 的点乘
    25. vec3 specular = specularStrength * spec * lightColor;//镜面反射光
    26. vec3 result = (ambient + diffuse + specular) * objectColor;//总效果
    27. FragColor = vec4(result, 1.0);
    28. }
    1. #include "widget.h"
    2. #include <QOpenGLShaderProgram>
    3. #include <QTimer>
    4. #include <QTime>
    5. static uint VBO, VAO, lightVAO;
    6. const float vertices[] = {
    7. //顶点坐标 法向量(每个面上的点法向量是相同的)
    8. -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
    9. 0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
    10. 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
    11. 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
    12. -0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
    13. -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
    14. -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
    15. 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
    16. 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
    17. 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
    18. -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
    19. -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
    20. -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
    21. -0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
    22. -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
    23. -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
    24. -0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
    25. -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
    26. 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
    27. 0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
    28. 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
    29. 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
    30. 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
    31. 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
    32. -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
    33. 0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
    34. 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
    35. 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
    36. -0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
    37. -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
    38. -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
    39. 0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
    40. 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
    41. 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
    42. -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
    43. -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f
    44. };
    45. static const QVector3D lightColor(1.0f, 1.0f, 1.0f);
    46. //static const QVector3D lightColor(0.33f, 0.42f, 0.18f);
    47. static const QVector3D objectColor(1.0f, 0.5f, 0.31f);
    48. static const QVector3D lightPos(1.2f, 1.0f, 2.0f);//光源位置
    49. static const QVector3D viewPos(0.0,0.0,5.0);//摄像机/眼睛位置
    50. Widget::Widget(QWidget *parent) : QOpenGLWidget(parent)
    51. {
    52. auto timer = new QTimer(this);
    53. connect(timer,&QTimer::timeout,this,[this]{update();});
    54. timer->start(300);
    55. }
    56. Widget::~Widget()
    57. {
    58. makeCurrent();
    59. glDeleteBuffers(1,&VBO);
    60. glDeleteVertexArrays(1,&VAO);
    61. glDeleteVertexArrays(1,&lightVAO);
    62. doneCurrent();
    63. }
    64. void Widget::initializeGL()
    65. {
    66. initializeOpenGLFunctions();
    67. glGenVertexArrays(1, &VAO);
    68. glBindVertexArray(VAO);
    69. glGenBuffers(1, &VBO);
    70. glBindBuffer(GL_ARRAY_BUFFER, VBO);
    71. glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    72. {
    73. glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), nullptr);
    74. glEnableVertexAttribArray(0);
    75. glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3*sizeof(float)));
    76. glEnableVertexAttribArray(1);
    77. }
    78. glGenVertexArrays(1, &lightVAO);
    79. glBindVertexArray(lightVAO);
    80. {
    81. glBindBuffer(GL_ARRAY_BUFFER, VBO);
    82. glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), nullptr);
    83. glEnableVertexAttribArray(0);
    84. }
    85. {
    86. shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex,":/shapes.vert");
    87. shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment,":/shapes.frag");
    88. if(!shaderProgram.link())
    89. qDebug()<<"着色器程序1编译错误信息:"<<shaderProgram.log();
    90. shaderProgram.bind();
    91. shaderProgram.setUniformValue("objectColor",objectColor);
    92. shaderProgram.setUniformValue("lightColor",lightColor);
    93. shaderProgram.setUniformValue("lightPos",lightPos);
    94. shaderProgram.setUniformValue("viewPos",viewPos);
    95. }
    96. {
    97. lightShaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex,":/light.vert");
    98. lightShaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment,":/light.frag");
    99. if(!lightShaderProgram.link())
    100. qDebug()<<"着色器程序2编译错误信息:"<<lightShaderProgram.log();
    101. lightShaderProgram.bind();
    102. lightShaderProgram.setUniformValue("lightColor",lightColor);
    103. }
    104. }
    105. void Widget::paintGL()
    106. {
    107. glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    108. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    109. //投影矩阵
    110. QMatrix4x4 projection;
    111. projection.perspective(60, //画面视野的角度 人眼在头部不动的情况下,视野大概为60°
    112. (float)width()/height(), //窗口比例
    113. 0.1f,100);//参数三和四表示距离摄像机多近个多远范围内的物体要被显示。超出这个范围的物体将无法被显示。
    114. //视图矩阵
    115. QMatrix4x4 view;
    116. view.setToIdentity();//对矩阵进行单位化,保证所有矩阵运算都会在一个单位矩阵上进行
    117. view.lookAt(QVector3D(2, 2, 2), //眼睛的位置
    118. QVector3D(0, 0, 0), //眼睛看的位置
    119. QVector3D(0, 1, 0)); //此参数表示方向,相对于眼睛向上的方向。
    120. //模型矩阵
    121. QMatrix4x4 model;
    122. model.setToIdentity();
    123. model.rotate(QTime::currentTime().msec(), 1.0f, 5.0f, 0.5f);//旋转 该矩阵将坐标绕矢量 (x, y, z) 旋转angle度
    124. model.scale(0.6f);//缩放
    125. {
    126. shaderProgram.bind();
    127. shaderProgram.setUniformValue("projection", projection);
    128. shaderProgram.setUniformValue("model", model);
    129. shaderProgram.setUniformValue("view", view);
    130. glBindVertexArray(VAO);
    131. glDrawArrays(GL_TRIANGLES,0,36);
    132. }
    133. {
    134. QVector3D lightPos(0.f, 1.0f, -2.0f);
    135. model.setToIdentity();
    136. model.translate(lightPos);
    137. model.rotate(1.0, 1.0f, 5.0f, 0.5f);
    138. model.scale(0.2f);
    139. lightShaderProgram.bind();
    140. lightShaderProgram.setUniformValue("projection", projection);
    141. lightShaderProgram.setUniformValue("view", view);
    142. lightShaderProgram.setUniformValue("model", model);
    143. glBindVertexArray(lightVAO);
    144. glDrawArrays(GL_TRIANGLES,0,36);
    145. }
    146. }

  • 相关阅读:
    Android之自定义相册文件选择器
    算法学习打卡day41|栈和队列:栈和队列相互实现、括号匹配、逆波兰表达式、滑动窗口最大值问题、求前 K 个高频元素
    UUCTF(公共赛道)
    软件工程毕业设计课题(14)基于python的毕业设计python运动场地预约系统毕设作品源码
    gbase8a 认证培训课后题(一)
    单元测试原则 first air
    Retrofit2 完全解析 探索与okhttp之间的关系
    Centos7系统使用systemd配置dotnet项目开机自启动
    [Java反序列化]—CommonsCollections4
    Linux 安全 - 扩展属性xattr
  • 原文地址:https://blog.csdn.net/kenfan1647/article/details/124963796