光照--贴图
https://learnopengl-cn.github.io/02%20Lighting/04%20Lighting%20maps/
https://www.jianshu.com/p/855ce8d81849
#include "widget.h" #include <QDebug> #include <QTimer> // lighting static QVector3D lightPos(1.2f, 1.0f, 2.0f); QtFunctionWidget::QtFunctionWidget(QWidget *parent) : QOpenGLWidget (parent), vbo(QOpenGLBuffer::VertexBuffer) { camera = new Camera(QVector3D(0.0f, 0.0f, 3.0f)); m_bLeftPressed = false; m_pTimer = new QTimer(this); connect(m_pTimer, &QTimer::timeout, this, [=]{ m_nTimeValue += 1; update(); }); m_pTimer->start(40);//25 fps } QtFunctionWidget::~QtFunctionWidget(){ makeCurrent(); lightVAO.destroy(); cubeVAO.destroy(); vbo.destroy(); if (m_pDiffuseMap) { delete m_pDiffuseMap; } if (m_pSpecularMap) { delete m_pSpecularMap; } doneCurrent(); } void QtFunctionWidget::initializeGL(){ this->initializeOpenGLFunctions(); createShader(); // set up vertex data (and buffer(s)) and configure vertex attributes // ------------------------------------------------------------------ float vertices[] = { // positions // normals // texture coords -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, -0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, -0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, -0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f, 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, -0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f }; vbo.create(); vbo.bind(); vbo.allocate(vertices, sizeof(vertices)); { QOpenGLVertexArrayObject::Binder vaoBind(&cubeVAO); //// position attribute // int attr = -1; // attr = lightingShader.attributeLocation("aPos"); // lightingShader.setAttributeBuffer(attr, GL_FLOAT, 0, 3, sizeof(GLfloat) * 6); // lightingShader.enableAttributeArray(attr); // attr = lightingShader.attributeLocation("aNormal"); // lightingShader.setAttributeBuffer(attr, GL_FLOAT, sizeof(GLfloat) * 3, 3, sizeof(GLfloat) * 6); // lightingShader.enableAttributeArray(attr); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float))); glEnableVertexAttribArray(1); glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float))); glEnableVertexAttribArray(2); } { QOpenGLVertexArrayObject::Binder vaoBind(&lightVAO); //// position attribute // int attr = -1; // attr = lightingShader.attributeLocation("aPos"); // lightingShader.setAttributeBuffer(attr, GL_FLOAT, 0, 3, sizeof(GLfloat) * 6); // lightingShader.enableAttributeArray(attr); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); } // load textures (we now use a utility function to keep the code more organized) // ----------------------------------------------------------------------------- m_pDiffuseMap = loadTexture(":/image/container2.png"); m_pSpecularMap = loadTexture(":/image/container2_specular.png"); // shader configuration // -------------------- lightingShader.bind(); lightingShader.setUniformValue("material.diffuse", 0); lightingShader.setUniformValue("material.specular", 1); lightingShader.release(); vbo.release(); // configure global opengl state // ----------------------------- glEnable(GL_DEPTH_TEST); } void QtFunctionWidget::resizeGL(int w, int h){ glViewport(0, 0, w, h); } void QtFunctionWidget::paintGL(){ // input // ----- camera->processInput(0.5f);//speed // render // ------ glClearColor(0.1f, 0.1f, 0.1f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // be sure to activate shader when setting uniforms/drawing objects lightingShader.bind(); lightingShader.setUniformValue("light.position", lightPos); lightingShader.setUniformValue("viewPos", camera->position); // light properties lightingShader.setUniformValue("light.ambient", QVector3D(0.2f, 0.2f, 0.2f)); lightingShader.setUniformValue("light.diffuse", QVector3D(0.5f, 0.5f, 0.5f)); lightingShader.setUniformValue("light.specular", QVector3D(1.0f, 1.0f, 1.0f)); // material properties lightingShader.setUniformValue("material.shininess", 64.0f); // view/projection transformations QMatrix4x4 projection; projection.perspective(camera->zoom, 1.0f * width() / height(), 0.1f, 100.0f); QMatrix4x4 view = camera->getViewMatrix(); lightingShader.setUniformValue("projection", projection); lightingShader.setUniformValue("view", view); // world transformation QMatrix4x4 model; lightingShader.setUniformValue("model", model); // bind diffuse map glActiveTexture(GL_TEXTURE0); m_pDiffuseMap->bind(); // bind specular map glActiveTexture(GL_TEXTURE1); m_pSpecularMap->bind(); {// render the cube QOpenGLVertexArrayObject::Binder vaoBind(&cubeVAO); glDrawArrays(GL_TRIANGLES, 0, 36); } lightingShader.release(); // also draw the lamp object lampShader.bind(); lampShader.setUniformValue("projection", projection); lampShader.setUniformValue("view", view); model = QMatrix4x4(); model.translate(lightPos); model.scale(0.2f); // a smaller cube lampShader.setUniformValue("model", model); { QOpenGLVertexArrayObject::Binder vaoBind(&lightVAO); glDrawArrays(GL_TRIANGLES, 0, 36); } lampShader.release(); } void QtFunctionWidget::keyPressEvent(QKeyEvent *event) { int key = event->key(); if (key >= 0 && key < 1024) camera->keys[key] = true; } void QtFunctionWidget::keyReleaseEvent(QKeyEvent *event) { int key = event->key(); if (key >= 0 && key < 1024) camera->keys[key] = false; } void QtFunctionWidget::mousePressEvent(QMouseEvent *event) { if(event->button() == Qt::LeftButton){ m_bLeftPressed = true; m_lastPos = event->pos(); } } void QtFunctionWidget::mouseReleaseEvent(QMouseEvent *event) { Q_UNUSED(event); m_bLeftPressed = false; } void QtFunctionWidget::mouseMoveEvent(QMouseEvent *event) { if (m_bLeftPressed) { int xpos = event->pos().x(); int ypos = event->pos().y(); int xoffset = xpos - m_lastPos.x(); int yoffset = m_lastPos.y() - ypos; m_lastPos = event->pos(); camera->processMouseMovement(xoffset, yoffset); } } void QtFunctionWidget::wheelEvent(QWheelEvent *event) { QPoint offset = event->angleDelta(); camera->processMouseScroll(offset.y()/20.0f); } bool QtFunctionWidget::createShader() { bool success = lightingShader.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shader/lighting_maps.vert"); if (!success) { qDebug() << "shaderProgram addShaderFromSourceFile failed!" << lightingShader.log(); return success; } success = lightingShader.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shader/lighting_maps.frag"); if (!success) { qDebug() << "shaderProgram addShaderFromSourceFile failed!" << lightingShader.log(); return success; } success = lightingShader.link(); if(!success) { qDebug() << "shaderProgram link failed!" << lightingShader.log(); } success = lampShader.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shader/lamp.vert"); if (!success) { qDebug() << "shaderProgram addShaderFromSourceFile failed!" << lampShader.log(); return success; } success = lampShader.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shader/lamp.frag"); if (!success) { qDebug() << "shaderProgram addShaderFromSourceFile failed!" << lampShader.log(); return success; } success = lampShader.link(); if(!success) { qDebug() << "shaderProgram link failed!" << lampShader.log(); } return success; } QOpenGLTexture *QtFunctionWidget::loadTexture(const QString &path) { QOpenGLTexture* pTexture = new QOpenGLTexture(QImage(path), QOpenGLTexture::GenerateMipMaps); if(!pTexture->isCreated()){ qDebug() << "Failed to load texture"; } // set the texture wrapping parameters pTexture->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat); //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); pTexture->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat); //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // set texture filtering parameters pTexture->setMinificationFilter(QOpenGLTexture::Linear); //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); pTexture->setMagnificationFilter(QOpenGLTexture::Linear); return pTexture; }
#ifndef QTFUNCTIONWIDGET_H #define QTFUNCTIONWIDGET_H #include <QOpenGLWidget> #include <QOpenGLShaderProgram> #include <QOpenGLFunctions> #include <QOpenGLVertexArrayObject> #include <QOpenGLBuffer> #include <QOpenGLTexture> #include "Camera.h" class QtFunctionWidget : public QOpenGLWidget, protected QOpenGLFunctions { public: QtFunctionWidget(QWidget *parent = nullptr); ~QtFunctionWidget() Q_DECL_OVERRIDE; protected: virtual void initializeGL() Q_DECL_OVERRIDE; virtual void resizeGL(int w, int h) Q_DECL_OVERRIDE; virtual void paintGL() Q_DECL_OVERRIDE; void keyPressEvent(QKeyEvent *event) Q_DECL_OVERRIDE; void keyReleaseEvent(QKeyEvent *event) Q_DECL_OVERRIDE; void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE; void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE; void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE; private: bool createShader(); QOpenGLTexture* loadTexture(const QString& path); private: QOpenGLShaderProgram lightingShader, lampShader; QOpenGLBuffer vbo; QOpenGLVertexArrayObject cubeVAO, lightVAO; QOpenGLTexture* m_pDiffuseMap = nullptr; QOpenGLTexture* m_pSpecularMap = nullptr; QTimer* m_pTimer = nullptr; int m_nTimeValue = 0; // camera std::unique_ptr<Camera> camera; bool m_bLeftPressed; QPoint m_lastPos; }; #endif // QTFUNCTIONWIDGET_H
#version 330 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec3 aNormal; layout (location = 2) in vec2 aTexCoords; out vec3 FragPos; out vec3 Normal; out vec2 TexCoords; uniform mat4 model; uniform mat4 view; uniform mat4 projection; void main() { FragPos = vec3(model * vec4(aPos, 1.0)); Normal = mat3(transpose(inverse(model))) * aNormal; TexCoords = aTexCoords; gl_Position = projection * view * vec4(FragPos, 1.0); }
#version 330 core out vec4 FragColor; struct Material { sampler2D diffuse; sampler2D specular; float shininess; }; struct Light { vec3 position; vec3 ambient; vec3 diffuse; vec3 specular; }; in vec3 FragPos; in vec3 Normal; in vec2 TexCoords; uniform vec3 viewPos; uniform Material material; uniform Light light; void main() { // ambient vec3 ambient = light.ambient * texture(material.diffuse, TexCoords).rgb; // diffuse vec3 norm = normalize(Normal); vec3 lightDir = normalize(light.position - FragPos); float diff = max(dot(norm, lightDir), 0.0); vec3 diffuse = light.diffuse * diff * texture(material.diffuse, TexCoords).rgb; // specular vec3 viewDir = normalize(viewPos - FragPos); vec3 reflectDir = reflect(-lightDir, norm); float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess); vec3 specular = light.specular * spec * texture(material.specular, TexCoords).rgb; vec3 result = ambient + diffuse + specular; FragColor = vec4(result, 1.0); }