OpenGL lightmaps

1 Introduction

Objects in the real world usually do not contain only one material, but are composed of multiple materials. Think of a car: its skin is very shiny, the windows partially reflect the surrounding environment, the tires are not as shiny so it has no specular highlights, and the wheels are very shiny.

2. Diffuse map

Using an image overlaying the object allows us to index its individual color values ​​on a per-fragment basis, which is a texture image that represents all the diffuse colors of the object.

This time we'll store the texture as a Material struct sampler2D. vec3We replace the diffuse color vector defined earlier with a diffuse map. Removed the ambient material color vector, since the ambient color is equal to the diffuse color in almost all cases, so we don't need to store them separately:

struct Material {
    sampler2D diffuse;
    vec3      specular;
    float     shininess;
}; 
...
in vec2 TexCoords;

Next we just need to sample the fragment's diffuse color value from the texture:

    vec3 diffuseTexColor = vec3(texture(material.diffuse,TexCoords));

    //diffuse
    vec3 norm = normalize(outNormal);
    vec3 lightDir = normalize(lightPos - FragPos);
    float diff = max(dot(norm, lightDir), 0.0);
    vec3 diffuse = light.diffuse * diff * diffuseTexColor;

Don't forget to set the ambient material color to the same value as the diffuse material color.

    //ambinet
    vec3 ambient = light.ambient * diffuseTexColor;

3. Specular light map

You might notice that the specular highlights look a little weird, since our objects are mostly wood, and we know wood shouldn't have such a strong specular highlight. We could fix this by setting the object's specular material to vec3(0.0), but this would also mean that the steel frame of the box would no longer be able to show specular highlights, as we know steel should have some specular highlights.

We can also use a dedicated texture map for specular highlights . This also means that we need to generate a black and white texture to define the specular light intensity of each part of the object.

Since the box is mostly made of wood, and the wood material is supposed to have no specular highlights, the entire wood part of the diffuse texture is converted to black. The specular intensity of the steel frame of the box varies slightly, the steel itself is more susceptible to specular highlights, while the cracks are not.

Next update the material properties of the fragment shader to accept one sampler2Dinstead of vec3a specular component:

struct Material {
    sampler2D diffuse;
    sampler2D specular;
    float     shininess;
};

4. Examples 

 

#include "myopenglwidget.h"
#include <QMatrix4x4>
#include <QTime>
#include <QTimer>
#include <math.h>
#include <QDebug>

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
};

GLuint indices[] = {
    0, 1, 3,
    1, 2, 3
};


GLuint VBO, VAO,EBO,lightVAO;
GLuint shaderProgram;

QVector3D lightPos(1.2f,1.0f,2.0f);
QVector3D lightColor(1.0f,1.0f,1.0f);
QVector3D objectColor(1.0f,0.5f,0.31f);

QTimer *timer;
QTime gtime;

QVector<QVector3D> cubePositions = {
  QVector3D( 0.0f,  0.0f,  0.0f),
  QVector3D( 2.0f,  5.0f, -15.0f),
  QVector3D(-1.5f, -2.2f, -2.5f),
  QVector3D(-3.8f, -2.0f, -12.3f),
  QVector3D( 2.4f, -0.4f, -3.5f),
  QVector3D(-1.7f,  3.0f, -7.5f),
  QVector3D( 1.3f, -2.0f, -2.5f),
  QVector3D( 1.5f,  2.0f, -2.5f),
  QVector3D( 1.5f,  0.2f, -1.5f),
  QVector3D(-1.3f,  1.0f, -1.5f)
};

float fov = 45.0f;

MyOpenGLWidget::MyOpenGLWidget(QWidget *parent)
    : QOpenGLWidget(parent)
{
    cameraPos = QVector3D( 0.0f,  0.0f,  5.0f);//摄像机位置
    cameraTarget = QVector3D( 0.0f,  0.0f,  0.0f);//摄像机看到的位置
    cameraDirection = QVector3D(cameraPos - cameraTarget);//摄像机的方向
    cameraDirection.normalize();

    up = QVector3D(0.0f,  1.0f,  0.0f);
    cameraRight = QVector3D::crossProduct(up,cameraDirection);//两个向量叉乘的结果会同时垂直于两向量,因此我们会得到指向x轴正方向的那个向量
    cameraRight.normalize();

    cameraUp = QVector3D::crossProduct(cameraDirection,cameraRight);
    cameraFront = QVector3D( 0.0f,  0.0f,  -1.0f);

    timer = new QTimer();
    timer->start(50);
    gtime.start();
    connect(timer,&QTimer::timeout,[=]{
        update();
    });

    setFocusPolicy(Qt::StrongFocus);
    //setMouseTracking(true);


}

void MyOpenGLWidget::initializeGL()
{
    initializeOpenGLFunctions();

    m_program = new QOpenGLShaderProgram();
    m_program->addShaderFromSourceFile(QOpenGLShader::Vertex,":/shapes.vert");
    m_program->addShaderFromSourceFile(QOpenGLShader::Fragment,":/shapes.frag");
    m_program->link();
    qDebug()<<m_program->log();

    m_lightProgram = new QOpenGLShaderProgram();
    m_lightProgram->addShaderFromSourceFile(QOpenGLShader::Vertex,":/light.vert");
    m_lightProgram->addShaderFromSourceFile(QOpenGLShader::Fragment,":/light.frag");
    m_lightProgram->link();


    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);

    glBindVertexArray(VAO);//绑定VAO
    glBindBuffer(GL_ARRAY_BUFFER, VBO);//顶点缓冲对象的缓冲类型是GL_ARRAY_BUFFER
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//把顶点数据复制到缓冲的内存中GL_STATIC_DRAW :数据不会或几乎不会改变。

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);

    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3*sizeof(GLfloat)));
    glEnableVertexAttribArray(1);

    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6*sizeof(GLfloat)));
    glEnableVertexAttribArray(2);

    glGenBuffers(1, &EBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);


    glGenVertexArrays(1, &lightVAO);
    glGenBuffers(1, &VBO);

    glBindVertexArray(lightVAO);//绑定VAO
    glBindBuffer(GL_ARRAY_BUFFER, VBO);//顶点缓冲对象的缓冲类型是GL_ARRAY_BUFFER
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//把顶点数据复制到缓冲的内存中GL_STATIC_DRAW :数据不会或几乎不会改变。

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, 0);


    m_program->bind();
    m_program->setUniformValue("lightPos",lightPos);
    m_program->setUniformValue("viewPos",cameraPos);
    m_program->setUniformValue("material.shininess", 32.0f);

    m_diffseTexture = new QOpenGLTexture(QImage(":/container2.png").mirrored());
    m_program->setUniformValue("material.diffuse",0);

    m_specularTexture = new QOpenGLTexture(QImage(":/container2_specular.png").mirrored());
    m_program->setUniformValue("material.specular",1);

    m_lightProgram->bind();
    m_lightProgram->setUniformValue("lightColor",lightColor);

    glBindVertexArray(0);//解绑VAO


}

void MyOpenGLWidget::paintGL()
{
    glClearColor(0.2f,0.3f,0.3f,1.0f);
    glEnable(GL_DEPTH_TEST);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    QMatrix4x4 model;
    QMatrix4x4 view;
    float time = gtime.elapsed()/50.0;
    //int time = QTime::currentTime().msec();

    QMatrix4x4 projection;
    projection.perspective(fov,(float)( width())/(height()),0.1,100);

    view.lookAt(cameraPos,cameraPos + cameraFront,up);

    m_program->bind();
    m_program->setUniformValue("projection",projection);
    m_program->setUniformValue("view",view);
    lightColor.setX(sin(time/100 * 2.0f));
    lightColor.setY(sin(time/100 * 0.7f));
    lightColor.setZ(sin(time/100 * 1.3f));
    QVector3D diffuseColor = QVector3D(0.3f,0.3f,0.3f);
    QVector3D ambinetColor = QVector3D(0.7f,0.7f,0.7f);
    m_program->setUniformValue("light.ambient",  ambinetColor);
    m_program->setUniformValue("light.diffuse",  diffuseColor); // 将光照调暗了一些以搭配场景
    m_program->setUniformValue("light.specular", QVector3D(1.0,1.0,1.0));
    m_diffseTexture->bind(0);
    m_specularTexture->bind(1);
    glBindVertexArray(VAO);//绑定VAO


    model.rotate(time,1.0f,1.0f,0.5f);
    m_program->setUniformValue("model",model);
    glDrawArrays(GL_TRIANGLES,0,36);

    m_lightProgram->bind();
    m_lightProgram->setUniformValue("projection",projection);
    m_lightProgram->setUniformValue("view",view);
    //m_lightProgram->setUniformValue("lightColor",lightColor);

    model.setToIdentity();
    model.translate(lightPos);
    model.rotate(1.0f,1.0f,5.0f,0.5f);
    model.scale(0.2);
    m_lightProgram->setUniformValue("model",model);

    glBindVertexArray(lightVAO);//绑定VAO
    glDrawArrays(GL_TRIANGLES,0,36);

//    foreach(auto pos , cubePositions)
//    {
//        model.setToIdentity();
//        model.translate(pos);
//        //model.rotate(time,1.0f,5.0f,3.0f);
//        m_program->setUniformValue("model",model);
//        glDrawArrays(GL_TRIANGLES,0,36);
//    }

}

void MyOpenGLWidget::resizeGL(int w, int h)
{

}

void MyOpenGLWidget::keyPressEvent(QKeyEvent *event)
{
    qDebug()<<event->key();
    cameraSpeed = 2.5 * 100 / 1000.0;
    switch (event->key()) {
    case Qt::Key_W:{
        cameraPos += cameraSpeed * cameraFront;
    }
        break;
    case Qt::Key_S:{
        cameraPos -= cameraSpeed * cameraFront;
    }
        break;
    case Qt::Key_A:{
        cameraPos -= cameraSpeed * cameraRight;
    }
        break;
    case Qt::Key_D:{
        cameraPos += cameraSpeed * cameraRight;
    }
        break;
    default:
        break;

    }
    update();
}
float PI = 3.1415926;
QPoint deltaPos;
void MyOpenGLWidget::mouseMoveEvent(QMouseEvent *event)
{
//    static float yaw = -90;
//    static float pitch = 0;
//    static QPoint lastPos(width()/2,height()/2);
//    auto currentPos = event->pos();
//    deltaPos = currentPos-lastPos;
//    lastPos=currentPos;
//    float sensitivity = 0.1f;
//    deltaPos *= sensitivity;
//    yaw += deltaPos.x();
//    pitch -= deltaPos.y();
//    if(pitch > 89.0f) pitch = 89.0f;
//    if(pitch < -89.0f) pitch = -89.0f;
//    cameraFront.setX(cos(yaw*PI/180.0) * cos(pitch *PI/180));
//    cameraFront.setY(sin(pitch*PI/180));
//    cameraFront.setZ(sin(yaw*PI/180) * cos(pitch *PI/180));
//    cameraFront.normalize();
//    update();
}

void MyOpenGLWidget::wheelEvent(QWheelEvent *event)
{
    if(fov >= 1.0f && fov <= 75.0f)
        fov -= event->angleDelta().y()/120;
    if(fov <= 1.0f)
        fov = 1.0f;
    if(fov >= 75.0f)
        fov = 75.0f;

    update();
}

Guess you like

Origin blog.csdn.net/wzz953200463/article/details/131152394