(本文是LearnOpenGL的学习笔记, 教程中文翻译地址https://learnopengl-cn.github.io/(备用地址https://learnopengl-cn.readthedocs.io/zh/latest/),写于 2020-2-4 ,并在 2021-9-7 进行了更新)
0.前言前面学习了LearnOpenGL的入门章节,本文开始学习光照 (Lighting) 的颜色 (Colors)。
1.如何实现颜色可以数字化的由红色(Red)、绿色(Green)和蓝色(Blue)三个分量组成,它们通常被缩写为RGB。我们在现实生活中看到某一物体的颜色并不是这个物体真正拥有的颜色,而是它所反射的(Reflected)颜色。换句话说,那些不能被物体所吸收(Absorb)的颜色(被拒绝的颜色)就是我们能够感知到的物体的颜色。
当我们在OpenGL中创建一个光源时,我们给光源一个颜色(如白色)。当我们把光源的颜色与物体的颜色值相乘,所得到的就是这个物体所反射的颜色(也就是我们所感知到的颜色)。
gl_FragColor = vec4(lightColor * objectColor, 1.0);
接下来就是利用之前学的顶点的知识在场景中绘制了两个盒子,一个光源(lamp),一个反射光照颜色的物体(lighting)。如果把物体的光照向量改为青色 vec3(0,1,1) ,那么反射的颜色也相应地改变了。
(项目git链接:https://github.com/gongjianbo/OpenGLwithQtWidgets.git)
我的GLColors类实现效果:
GLColors类代码:
#pragma once
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//光照颜色
//QOpenGLWidget窗口上下文
//QOpenGLFunctions访问OpenGL接口,可以不继承作为成员变量使用
class GLColors
: public QOpenGLWidget
, protected QOpenGLFunctions_3_3_Core
{
Q_OBJECT
public:
explicit GLColors(QWidget *parent = nullptr);
~GLColors();
protected:
//【】继承QOpenGLWidget后重写这三个虚函数
//设置OpenGL资源和状态。在第一次调用resizeGL或paintGL之前被调用一次
void initializeGL() override;
//渲染OpenGL场景,每当需要更新小部件时使用
void paintGL() override;
//设置OpenGL视口、投影等,每当尺寸大小改变时调用
void resizeGL(int width, int height) override;
//鼠标操作,重载Qt的事件处理
void mousePressEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void wheelEvent(QWheelEvent *event) override;
private:
void initShader();
private:
//着色器程序
QOpenGLShaderProgram lightingShader,lampShader;
//顶点数组对象
QOpenGLVertexArrayObject lightingVao,lampVao;
//顶点缓冲
QOpenGLBuffer vbo;
//
QVector3D rotationAxis;
QQuaternion rotationQuat;
//透视投影的fovy参数,视野范围
float projectionFovy{ 45.0f };
//鼠标位置
QPoint mousePos;
};
#include "GLColors.h"
#include
#include
#include
GLColors::GLColors(QWidget *parent)
: QOpenGLWidget(parent)
{
}
GLColors::~GLColors()
{
//initializeGL在显示时才调用,释放未初始化的会异常
if(!isValid())
return;
//QOpenGLWidget
//三个虚函数不需要makeCurrent,对应的操作已由框架完成
//但是释放时需要设置当前上下文
makeCurrent();
vbo.destroy();
lightingVao.destroy();
lampVao.destroy();
doneCurrent();
}
void GLColors::initializeGL()
{
//为当前上下文初始化OpenGL函数解析
initializeOpenGLFunctions();
initShader();
//方块的顶点
float vertices[] = {
-0.5f, -0.5f, -0.5f,
0.5f, -0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
-0.5f, 0.5f, -0.5f,
-0.5f, -0.5f, -0.5f,
-0.5f, -0.5f, 0.5f,
0.5f, -0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
-0.5f, -0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, -0.5f,
-0.5f, -0.5f, -0.5f,
-0.5f, -0.5f, -0.5f,
-0.5f, -0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
0.5f, 0.5f, -0.5f,
0.5f, -0.5f, -0.5f,
0.5f, -0.5f, -0.5f,
0.5f, -0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
-0.5f, -0.5f, -0.5f,
0.5f, -0.5f, -0.5f,
0.5f, -0.5f, 0.5f,
0.5f, -0.5f, 0.5f,
-0.5f, -0.5f, 0.5f,
-0.5f, -0.5f, -0.5f,
-0.5f, 0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
0.5f, 0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, -0.5f,
};
vbo=QOpenGLBuffer(QOpenGLBuffer::VertexBuffer);
vbo.create();
//light vao
lightingVao.create();
lightingVao.bind();
vbo.bind();
vbo.allocate(vertices,sizeof(vertices));
//setAttributeBuffer(int location, GLenum type, int offset, int tupleSize, int stride = 0)
lightingShader.setAttributeBuffer(0, GL_FLOAT, 0, 3, sizeof(GLfloat) * 3);
lightingShader.enableAttributeArray(0);
vbo.release();
lightingVao.release();
//lamp vao
lampVao.create();
lampVao.bind();
vbo.bind();
//setAttributeBuffer(int location, GLenum type, int offset, int tupleSize, int stride = 0)
lampShader.setAttributeBuffer(0, GL_FLOAT, 0, 3, sizeof(GLfloat) * 3);
lampShader.enableAttributeArray(0);
vbo.release();
lampVao.release();
}
void GLColors::paintGL()
{
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
//清除深度缓冲
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//Z缓冲(Z-buffer),深度缓冲(Depth Buffer)。
glEnable(GL_DEPTH_TEST);
//draw lighting
lightingShader.bind();
lightingShader.setUniformValue("objectColor",QVector3D(1.0f,0.5f,0.31f));
lightingShader.setUniformValue("lightColor",QVector3D(1.0f,1.0f,1.0f));
QMatrix4x4 view; //观察矩阵
float radius = 20.0f;
view.translate(0.0f, 0.0f, -radius);
view.rotate(rotationQuat);
lightingShader.setUniformValue("view", view);
QMatrix4x4 projection; //透视投影
projection.perspective(projectionFovy, 1.0f * width() / height(), 0.1f, 100.0f);
lightingShader.setUniformValue("projection", projection);
QMatrix4x4 model;//模型矩阵
model.rotate(30, QVector3D(1.0f, 1.0f, 0.0f));
lightingShader.setUniformValue("model", model);
lightingVao.bind();
glDrawArrays(GL_TRIANGLES, 0, 36);
lightingVao.release();
lightingShader.release();
//draw lamp
lampShader.bind();
lampShader.setUniformValue("view", view);
lampShader.setUniformValue("projection", projection);
model = QMatrix4x4();
model.translate(QVector3D(1.0f, 1.0f, 0.0f));
model.rotate(30, QVector3D(1.0f, 1.0f, 0.0f));
//model.translate(QVector3D(1.2f, 1.0f, 2.0f));
model.scale(0.3f);
lampShader.setUniformValue("model", model);
lampVao.bind();
glDrawArrays(GL_TRIANGLES, 0, 36);
lampVao.release();
lampShader.release();
}
void GLColors::resizeGL(int width, int height)
{
glViewport(0, 0, width, height);
}
void GLColors::mousePressEvent(QMouseEvent *event)
{
event->accept();
mousePos = event->pos();
}
void GLColors::mouseReleaseEvent(QMouseEvent *event)
{
event->accept();
}
void GLColors::mouseMoveEvent(QMouseEvent *event)
{
event->accept();
//参照示例cube
QVector2D diff = QVector2D(event->pos()) - QVector2D(mousePos);
mousePos = event->pos();
QVector3D n = QVector3D(diff.y(), diff.x(), 0.0).normalized();
rotationAxis = (rotationAxis + n).normalized();
//不能对换乘的顺序
rotationQuat = QQuaternion::fromAxisAndAngle(rotationAxis, 2.0f) * rotationQuat;
update();
}
void GLColors::wheelEvent(QWheelEvent *event)
{
event->accept();
//fovy越小,模型看起来越大
if(event->delta() < 0){
//鼠标向下滑动为-,这里作为zoom out
projectionFovy += 0.5f;
if(projectionFovy > 90)
projectionFovy = 90;
}else{
//鼠标向上滑动为+,这里作为zoom in
projectionFovy -= 0.5f;
if(projectionFovy < 1)
projectionFovy = 1;
}
update();
}
void GLColors::initShader()
{
//lingting shader
//in输入,out输出,uniform从cpu向gpu发送
const char *lighting_vertex=R"(#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);
})";
const char *lighting_fragment=R"(#version 330 core
uniform vec3 objectColor;
uniform vec3 lightColor;
out vec4 FragColor;
void main()
{
FragColor = vec4(lightColor * objectColor, 1.0);
})";
//将source编译为指定类型的着色器,并添加到此着色器程序
if(!lightingShader.addCacheableShaderFromSourceCode(
QOpenGLShader::Vertex,lighting_vertex)){
qDebug()
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?