光照--材质
https://learnopengl-cn.github.io/02%20Lighting/03%20Materials/
https://www.jianshu.com/p/855ce8d81849
#include "QtFunctionWidget.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 = std::make_unique<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(); doneCurrent(); } void QtFunctionWidget::initializeGL(){ this->initializeOpenGLFunctions(); createShader(); // set up vertex data (and buffer(s)) and configure vertex attributes // ------------------------------------------------------------------ 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.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); // position attribute glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); // normal attribute glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float))); glEnableVertexAttribArray(1); } { 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, 6 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); } 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 QVector3D lightColor; lightColor.setX(sin(m_nTimeValue * /*2.0f*/0.1f)); lightColor.setY(sin(m_nTimeValue * /*0.7f*/0.035f)); lightColor.setZ(sin(m_nTimeValue * /*1.3f*/0.065f)); QVector3D diffuseColor = lightColor * 0.5f; // decrease the influence QVector3D ambientColor = diffuseColor * 0.2f; // low influence lightingShader.setUniformValue("light.ambient", ambientColor); lightingShader.setUniformValue("light.diffuse", diffuseColor); lightingShader.setUniformValue("light.specular", 1.0f, 1.0f, 1.0f); // material properties lightingShader.setUniformValue("material.ambient", QVector3D(1.0f, 0.5f, 0.31f)); lightingShader.setUniformValue("material.diffuse", QVector3D(1.0f, 0.5f, 0.31f)); lightingShader.setUniformValue("material.specular", QVector3D(0.5f, 0.5f, 0.5f)); // specular lighting doesn't have full effect on this object's material lightingShader.setUniformValue("material.shininess", 32.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); {// 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, ":/lighting_maps.vert"); if (!success) { qDebug() << "shaderProgram addShaderFromSourceFile failed!" << lightingShader.log(); return success; } success = lightingShader.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/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, ":/lamp.vert"); if (!success) { qDebug() << "shaderProgram addShaderFromSourceFile failed!" << lampShader.log(); return success; } success = lampShader.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/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; }
#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(); private: QOpenGLShaderProgram lightingShader, lampShader; QOpenGLBuffer vbo; QOpenGLVertexArrayObject cubeVAO, lightVAO; QTimer* m_pTimer = nullptr; int m_nTimeValue = 0; // camera std::unique_ptr<Camera> camera; bool m_bLeftPressed; QPoint m_lastPos; }; #endif // QTFUNCTIONWIDGET_H
camera
#include "Camera.h" #include <QDebug> Camera::Camera(QVector3D position, QVector3D up, float yaw, float pitch) : position(position), worldUp(up), front(-position), picth(pitch), yaw(yaw), movementSpeed(SPEED), mouseSensitivity(SENSITIVITY), zoom(ZOOM) { this->updateCameraVectors(); for(uint i = 0; i != 1024; ++i) keys[i] = false; } Camera::~Camera() { } // Returns the view matrix calculated using Euler Angles and the LookAt Matrix QMatrix4x4 Camera::getViewMatrix() { QMatrix4x4 view; view.lookAt(this->position, this->position + this->front, this->up); return view; } // Processes input received from any keyboard-like input system. Accepts input parameter in the form of camera defined ENUM (to abstract it from windowing systems) void Camera::processKeyboard(Camera_Movement direction, float deltaTime) { float velocity = this->movementSpeed * deltaTime; if (direction == FORWARD) this->position += this->front * velocity; if (direction == BACKWARD) this->position -= this->front * velocity; if (direction == LEFT) this->position -= this->right * velocity; if (direction == RIGHT) this->position += this->right * velocity; if (direction == UP) this->position += this->worldUp * velocity; if (direction == DOWN) this->position -= this->worldUp * velocity; } // Processes input received from a mouse input system. Expects the offset value in both the x and y direction. void Camera::processMouseMovement(float xoffset, float yoffset, bool constraintPitch) { xoffset *= this->mouseSensitivity; yoffset *= this->mouseSensitivity; this->yaw += xoffset; this->picth += yoffset; if (constraintPitch) { if (this->picth > 89.0f) this->picth = 89.0f; if (this->picth < -89.0f) this->picth = -89.0f; } this->updateCameraVectors(); } // Processes input received from a mouse scroll-wheel event. Only requires input on the vertical wheel-axis void Camera::processMouseScroll(float yoffset) { if (this->zoom >= 1.0f && this->zoom <= 45.0f) this->zoom -= yoffset; if (this->zoom > 45.0f) this->zoom = 45.0f; if (this->zoom < 1.0f) this->zoom = 1.0f; } void Camera::processInput(float dt) { if (keys[Qt::Key_W]) processKeyboard(FORWARD, dt); if (keys[Qt::Key_S]) processKeyboard(BACKWARD, dt); if (keys[Qt::Key_A]) processKeyboard(LEFT, dt); if (keys[Qt::Key_D]) processKeyboard(RIGHT, dt); if (keys[Qt::Key_E]) processKeyboard(UP, dt); if (keys[Qt::Key_Q]) processKeyboard(DOWN, dt); } void Camera::updateCameraVectors() { // Calculate the new Front vector QVector3D front; front.setX(cos(this->yaw) * cos(this->picth)); front.setY(sin(this->picth)); front.setZ(sin(this->yaw) * cos(this->picth)); this->front = front.normalized(); this->right = QVector3D::crossProduct(this->front, this->worldUp).normalized(); this->up = QVector3D::crossProduct(this->right, this->front).normalized(); }
#ifndef CAMERA_H #define CAMERA_H #include <QVector3D> #include <QMatrix4x4> #include <QKeyEvent> // Defines several possible options for camera movement. Used as abstraction to stay away from window-system specific input methods enum Camera_Movement { FORWARD, BACKWARD, LEFT, RIGHT, UP, DOWN }; // Default camera values const float YAW = -90.0f; const float PITCH = 0.0f; const float SPEED = 1.0f; const float SENSITIVITY = 0.01f; const float ZOOM = 45.0f; class Camera { public: Camera(QVector3D position = QVector3D(0.0f, 0.0f, 0.0f), QVector3D up = QVector3D(0.0f, 1.0f, 0.0f), float yaw = YAW, float pitch = PITCH); ~Camera(); QMatrix4x4 getViewMatrix(); void processMouseMovement(float xoffset, float yoffset, bool constraintPitch = true); void processMouseScroll(float yoffset); void processInput(float dt); QVector3D position; QVector3D worldUp; QVector3D front; QVector3D up; QVector3D right; //Eular Angles float picth; float yaw; //Camera options float movementSpeed; float mouseSensitivity; float zoom; //Keyboard multi-touch bool keys[1024]; private: void updateCameraVectors(); void processKeyboard(Camera_Movement direction, float deltaTime); }; #endif // CAMERA_H
light
#version 330 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec3 aNormal; out vec3 FragPos; out vec3 Normal; uniform mat4 model; uniform mat4 view; uniform mat4 projection; void main() { FragPos = vec3(model * vec4(aPos, 1.0)); Normal = mat3(transpose(inverse(model))) * aNormal; gl_Position = projection * view * vec4(FragPos, 1.0); }
#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 FragPos; in vec3 Normal; uniform vec3 viewPos; uniform Material material; uniform Light light; void main() { // ambient vec3 ambient = light.ambient * material.ambient; // diffuse vec3 norm = normalize(Normal); vec3 lightDir = normalize(light.position - FragPos); float diff = max(dot(norm, lightDir), 0.0); vec3 diffuse = light.diffuse * (diff * material.diffuse); // 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 * material.specular); vec3 result = ambient + diffuse + specular; FragColor = vec4(result, 1.0); }
lamp
#version 330 core layout (location = 0) in vec3 aPos; uniform mat4 model; uniform mat4 view; uniform mat4 projection; void main(){ gl_Position = projection * view * model * vec4(aPos, 1.0f); }
#version 330 core out vec4 FragColor; void main() { FragColor = vec4(1.0f); }