OpenGL入门第六步:材质

avatar
作者
筋斗云
阅读量:0

目录

结果显示

材质介绍

函数解析

具体代码


结果显示

材质介绍

当描述一个表面时,我们可以分别为三个光照分量定义一个材质颜色(Material Color):环境光照(Ambient Lighting)、漫反射光照(Diffuse Lighting)和镜面光照(Specular Lighting)。通过为每个分量指定一个颜色,我们就能够对表面的颜色输出有细粒度的控制了。现在,我们再添加一个反光度(Shininess)分量,结合上述的三个颜色,我们就有了全部所需的材质属性了。

为风氏光照模型的每个分量都定义一个颜色向量。ambient材质向量定义了在环境光照下这个表面反射的是什么颜色,通常与表面的颜色相同。diffuse材质向量定义了在漫反射光照下表面的颜色。漫反射颜色(和环境光照一样)也被设置为我们期望的物体颜色。specular材质向量设置的是表面上镜面高光的颜色(或者甚至可能反映一个特定表面的颜色)。最后,shininess影响镜面高光的散射/半径。有这4个元素定义一个物体的材质,我们能够模拟很多现实世界中的材质。devernay.free.fr中的一个表格展示了一系列材质属性,它们模拟了现实世界中的真实材质。下图展示了几组现实世界的材质参数值对我们的立方体的影响:

可以看到,通过正确地指定一个物体的材质属性,我们对这个物体的感知也就不同了。效果非常明显,但是要想获得更真实的效果,我们需要以更复杂的形状替换这个立方体。

函数解析

timerEvent(QTimerEvent *event)函数

initializeGL()函数绘制光源

顶点着色器

片段着色器 

环境光通常被认为是均匀地照亮场景的,所以直接用光源的环境光和材质的环境光相乘来简单表示。

漫反射光的强度取决于光线与表面法向量的夹角。通过归一化法向量和光线方向向量,然后计算它们的点积,就能得到光线与表面的夹角余弦值。夹角越小,漫反射光越强,所以用这个点积值来控制漫反射光的强度。

镜面反射光主要是模拟物体表面的高光效果。通过计算反射方向向量和观察方向向量的点积,并对结果进行幂运算,来模拟高光的集中和锐利程度。材质的 shininess 值越大,高光就越集中和锐利。

光源的绘制和前一次(基础光照)没有区别。 

paintGL()函数:传参进行绘制

具体代码

.h

#ifndef OPENGLWIDGET_H #define OPENGLWIDGET_H  #include <QOpenGLWidget> #include <QOpenGLShaderProgram> #include <QOpenGLBuffer> #include <QOpenGLVertexArrayObject> #include <QOpenGLTexture> #include <QElapsedTimer> #include "Camera.h"  QT_BEGIN_NAMESPACE namespace Ui { class openGLWidget; } QT_END_NAMESPACE  class openGLWidget : public QOpenGLWidget {     Q_OBJECT  public:     openGLWidget(QWidget *parent = nullptr);     ~openGLWidget(); protected:     virtual void timerEvent(QTimerEvent *event) override;     //鼠标事件     virtual void enterEvent(QEnterEvent *event) override;     virtual void leaveEvent(QEvent *event) override;     virtual void mouseMoveEvent(QMouseEvent *event) override;     virtual void wheelEvent(QWheelEvent *event) override;     virtual void keyPressEvent(QKeyEvent *event) override;     virtual void keyReleaseEvent(QKeyEvent *event) override;     //初始化     virtual void initializeGL() override;     virtual void resizeGL(int w, int h) override;     virtual void paintGL() override;  private:     QOpenGLShaderProgram lightingShader;     QOpenGLShaderProgram lightCubeShader;     QOpenGLBuffer vbo;     QOpenGLVertexArrayObject cubeVao;     QOpenGLVertexArrayObject lightVao;     QMatrix4x4 projection;     QMatrix4x4 view;     Camera camera {Camera(QVector3D(0.0f, 0.0f, 3.0f))};     QVector3D lightPos {QVector3D(1.2f, 1.0f, 2.0f)};     // 用 0 - 1 的值 直接表示颜色     QVector3D diffuseColor;     QVector3D ambientColor;     QElapsedTimer time;     float lastFrameTime {0.f};     struct {         bool W {false};         bool S {false};         bool A {false};         bool D {false};     } keys;  private:     Ui::openGLWidget *ui; }; #endif // OPENGLWIDGET_H 

.cpp

#include "openGLWidget.h" #include "./ui_openGLWidget.h"  #include <QOpenGLFunctions> #include <QKeyEvent> #include <QPainter> #include <QtMath>  openGLWidget::openGLWidget(QWidget *parent)     : QOpenGLWidget(parent)     , ui(new Ui::openGLWidget) {     ui->setupUi(this);     setMouseTracking(true); }  openGLWidget::~openGLWidget() {     makeCurrent();     lightVao.destroy();     cubeVao.destroy();     vbo.destroy();     doneCurrent();     delete ui; }  void openGLWidget::timerEvent(QTimerEvent *event) {     float s = time.elapsed() / 1000.0;     float delta = s - lastFrameTime;     lastFrameTime = s;     if (keys.W)         camera.ProcessKeyboard(FORWARD, delta);     if (keys.S)         camera.ProcessKeyboard(BACKWARD, delta);     if (keys.A)         camera.ProcessKeyboard(LEFT, delta);     if (keys.D)         camera.ProcessKeyboard(RIGHT, delta);     view = camera.GetViewMatrix();     QVector3D lightColor(qSin(lastFrameTime * 2.0), qSin(lastFrameTime * 0.7), qSin(lastFrameTime * 1.3));     diffuseColor = lightColor * 0.5;     ambientColor = lightColor * 0.2;     update(); }  void openGLWidget::enterEvent(QEnterEvent *event) {     // 隐藏鼠标指针,将指针置于窗口中心     setCursor(Qt::BlankCursor);     QCursor::setPos(mapToGlobal(rect().center())); }  void openGLWidget::leaveEvent(QEvent *event) {  }  void openGLWidget::mouseMoveEvent(QMouseEvent *event) {     float xoffset = rect().center().x() - event->x();     float yoffset = rect().center().y() - event->y();      float sensitivity = 0.1f; // change this value to your liking     xoffset *= sensitivity;     yoffset *= sensitivity;      camera.ProcessMouseMovement(xoffset, yoffset);      // 将指针置于窗口中心     QCursor::setPos(mapToGlobal(rect().center())); }  void openGLWidget::wheelEvent(QWheelEvent *event) {     float f = event->angleDelta().y() > 0 ? 1.0f : -1.0f;     camera.ProcessMouseScroll(f);     projection.setToIdentity();     projection.perspective(camera.Zoom, float(width()) / float(height()), 0.1f, 100.f); }  void openGLWidget::keyPressEvent(QKeyEvent *event) {     switch(event->key()) {     case Qt::Key_W:         keys.W = true;         break;     case Qt::Key_S:         keys.S = true;         break;     case Qt::Key_A:         keys.A = true;         break;     case Qt::Key_D:         keys.D = true;         break;     default:         return;     } }  void openGLWidget::keyReleaseEvent(QKeyEvent *event) {     switch(event->key()) {     case Qt::Key_W:         keys.W = false;         break;     case Qt::Key_S:         keys.S = false;         break;     case Qt::Key_A:         keys.A = false;         break;     case Qt::Key_D:         keys.D = false;         break;     default:         return;     } }  void openGLWidget::initializeGL() {     // 设置用来清空屏幕的颜色 这里设置为黑色     QOpenGLFunctions *f = context()->functions();     f->glClearColor(0.0f, 0.0f, 0.0f, 0.0f);      lightingShader.addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, R"(         #version 330 core         layout (location = 0) in vec3 aPos;         layout (location = 1) in vec3 aNormal;         out vec3 vFragPos;         out vec3 vNormal;         uniform mat4 uProjection;         uniform mat4 uView;         uniform mat4 uModel;          void main()         {             vFragPos = vec3(uModel * vec4(aPos, 1.0));             vNormal = mat3(transpose(inverse(uModel))) * aNormal;              gl_Position = uProjection * uView * uModel * vec4(aPos, 1.0);         }     )");     // 片段着色器     lightingShader.addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, R"(         #version 330 core         out vec4 FragColor;          struct Material {             vec3 ambient;             vec3 diffuse;             vec3 specular;             float shininess;         };          struct Light {             vec3 position;             vec3 ambient;             vec3 diffuse;             vec3 specular;         };          in vec3 vNormal;         in vec3 vFragPos;          uniform vec3 uViewPos;         uniform Material uMaterial;         uniform Light uLight;          void main()         {             // ambient             vec3 ambient = uLight.ambient * uMaterial.ambient;              // diffuse             vec3 norm = normalize(vNormal);             vec3 lightDir = normalize(uLight.position - vFragPos);             float diff = max(dot(norm, lightDir), 0.0);             vec3 diffuse = uLight.diffuse * (diff * uMaterial.diffuse);              // specular             vec3 viewDir = normalize(uViewPos - vFragPos);             vec3 reflectDir = reflect(-lightDir, norm);             float spec = pow(max(dot(viewDir, reflectDir), 0.0), uMaterial.shininess);             vec3 specular = uLight.specular * (spec * uMaterial.specular);              vec3 result = ambient + diffuse + specular;             FragColor = vec4(result, 1.0);         }     )");     // 编译链接     if(!lightingShader.link()) {         qDebug() << lightingShader.log();     };      //光源     lightCubeShader.addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, R"(         #version 330 core         layout (location = 0) in vec3 aPos;          uniform mat4 uModel;         uniform mat4 uView;         uniform mat4 uProjection;          void main()         {             gl_Position = uProjection * uView * uModel * vec4(aPos, 1.0);         }     )");      lightCubeShader.addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, R"(         #version 330 core         out vec4 FragColor;          void main()         {             FragColor = vec4(1.0); // set all 4 vector values to 1.0         }     )");     // 编译链接     if(!lightCubeShader.link()) {         qDebug() << lightCubeShader.log();     };      // 顶点数据     float vertices[] = {         -0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,         0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,         0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,         0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,         -0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,         -0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,          -0.5f, -0.5f,  0.5f,  0.0f,  0.0f,  1.0f,         0.5f, -0.5f,  0.5f,  0.0f,  0.0f,  1.0f,         0.5f,  0.5f,  0.5f,  0.0f,  0.0f,  1.0f,         0.5f,  0.5f,  0.5f,  0.0f,  0.0f,  1.0f,         -0.5f,  0.5f,  0.5f,  0.0f,  0.0f,  1.0f,         -0.5f, -0.5f,  0.5f,  0.0f,  0.0f,  1.0f,          -0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,         -0.5f,  0.5f, -0.5f, -1.0f,  0.0f,  0.0f,         -0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,         -0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,         -0.5f, -0.5f,  0.5f, -1.0f,  0.0f,  0.0f,         -0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,          0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,         0.5f,  0.5f, -0.5f,  1.0f,  0.0f,  0.0f,         0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,         0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,         0.5f, -0.5f,  0.5f,  1.0f,  0.0f,  0.0f,         0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,          -0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,         0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,         0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,         0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,         -0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,         -0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,          -0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,         0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,         0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,         0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,         -0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,         -0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f     };     // 创建VBO     vbo.create();     vbo.bind();     vbo.allocate(vertices, sizeof(vertices));      cubeVao.create();     cubeVao.bind();     lightingShader.enableAttributeArray(0);     lightingShader.setAttributeBuffer(0, GL_FLOAT, 0, 3, 6 * sizeof(float));     lightingShader.enableAttributeArray(1);     lightingShader.setAttributeBuffer(1, GL_FLOAT, 3 * sizeof(float), 3, 6 * sizeof(float));      lightVao.create();     lightVao.bind();     lightCubeShader.enableAttributeArray(0);     lightCubeShader.setAttributeBuffer(0, GL_FLOAT, 0, 3, 6 * sizeof(float));     startTimer(1);     time.start(); }  void openGLWidget::resizeGL(int w, int h) {     QOpenGLFunctions *f = context()->functions();     f->glViewport(0, 0, w, h);     projection.setToIdentity();     projection.perspective(camera.Zoom, float(w) / float(h), 0.1f, 100.f); }  void openGLWidget::paintGL() {     QOpenGLFunctions* f = context()->functions();     f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);     // 启用深度测试     f->glEnable(GL_DEPTH_TEST);      lightingShader.bind();     lightingShader.setUniformValue("uViewPos", camera.Position);     lightingShader.setUniformValue("uLight.position", lightPos);     lightingShader.setUniformValue("uLight.ambient", ambientColor);     lightingShader.setUniformValue("uLight.diffuse", diffuseColor);     lightingShader.setUniformValue("uLight.specular", 1.0f, 1.0f, 1.0f);      lightingShader.setUniformValue("uMaterial.ambient", 1.0f, 0.5f, 0.31f);     lightingShader.setUniformValue("uMaterial.diffuse", 1.0f, 0.5f, 0.31f);     lightingShader.setUniformValue("uMaterial.specular", 0.5f, 0.5f, 0.5f);     lightingShader.setUniformValue("uMaterial.shininess", 32.0f);      lightingShader.setUniformValue("uProjection", projection);     lightingShader.setUniformValue("uView", view);     lightingShader.setUniformValue("uModel", QMatrix4x4());     cubeVao.bind();     f->glDrawArrays(GL_TRIANGLES, 0, 36);      lightCubeShader.bind();     lightCubeShader.setUniformValue("uProjection", projection);     lightCubeShader.setUniformValue("uView", view);     QMatrix4x4 model;     model.translate(lightPos);     model.scale(0.2f);     lightCubeShader.setUniformValue("uModel", model);     lightVao.bind();     f->glDrawArrays(GL_TRIANGLES, 0, 36); } 

Camera.h参考前一篇

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!