当前位置: 首页 > news >正文

OpenGl实战笔记(3)基于qt5.15.2+mingw64+opengl实现光照变化效果

一、作用原理

1、作用
增强真实感:通过明暗变化模拟立体和材质。
体现空间感:让物体不再“平面”,更具三维效果。
表现材质特性:模拟金属、塑料等不同表面的反光。
实现动态光影:支持移动光源、阴影、高光等效果。
2、原理
OpenGL 光照效果基于 光与表面交互的数学模型,常见为 冯氏模型(Phong Model),包括:
环境光 Ambient 整体照亮,无方向,用于模拟环境反射光。
漫反射 Diffuse 与法线夹角有关,光越垂直表面越亮。
高光 Specular 反射光靠近视角方向时产生亮点,表现光滑表面反光。
3、常见光源类型
平行光:有方向,无位置(如太阳)。
点光源:有位置,向各方向发光(如灯泡)。
聚光灯:有方向和角度限制(如手电筒)。

二、实现效果
在这里插入图片描述
三、参考代码

#pragma once// 渲染模块接口定义(用于模块化设计)
#include "RenderModuleInterface.h"// Qt OpenGL 所需的类
#include <QOpenGLFunctions>              // 提供所有 OpenGL ES 2.0 函数
#include <QOpenGLShaderProgram>          // 管理顶点与片元着色器
#include <QOpenGLBuffer>                 // 管理 VBO(顶点缓冲对象)
#include <QOpenGLVertexArrayObject>      // 管理 VAO(顶点数组对象)
#include <QObject>                       // 支持 Qt 的信号槽机制// 光照渲染类,继承自 QObject(用于信号槽)
// 同时实现渲染接口 RenderModuleInterface,并继承 OpenGL 函数支持
class LightingRenderer : public QObject,public RenderModuleInterface,protected QOpenGLFunctions
{
public:// 初始化 OpenGL 状态、着色器、顶点数据等void initialize() override;// 视口大小改变时调用,设置 OpenGL 视口void resize(int w, int h) override;// 渲染主函数,绘制一帧图像void render() override;public slots:// 每帧更新函数,用于驱动动画等逻辑void onFrameUpdate();private:QOpenGLShaderProgram shader;         // 着色器程序对象(包含顶点 + 片元着色器)QOpenGLBuffer vbo;                   // 顶点缓冲对象,用于存储顶点数据QOpenGLVertexArrayObject vao;        // 顶点数组对象,保存顶点属性配置int width = 0, height = 0;           // 当前窗口宽高,用于设置视口bool isInitialized = false;          // 标志位,确保只初始化一次float t = 0.0f;                      // 用于控制动画变化的时间参数(如光源移动等)
};
#include "LightingRenderer.h"
#include <QMatrix4x4>
#include <QVector3D>
#include <QtMath>// 顶点着色器:传递位置、法线,并计算世界坐标和变换后的法线
static const char* lightingVert = R"(
#version 330 core
layout(location = 0) in vec3 position;
layout(location = 1) in vec3 normal;out vec3 FragPos;
out vec3 Normal;uniform mat4 u_mvp;   // 模型-视图-投影矩阵
uniform mat4 u_model; // 模型矩阵,用于变换法线和世界坐标void main()
{FragPos = vec3(u_model * vec4(position, 1.0));              // 计算世界坐标Normal = mat3(transpose(inverse(u_model))) * normal;        // 法线矩阵(保持正确方向)gl_Position = u_mvp * vec4(position, 1.0);                  // 最终顶点位置
})";// 片元着色器:实现漫反射光照
static const char* lightingFrag = R"(
#version 330 core
in vec3 FragPos;
in vec3 Normal;
out vec4 FragColor;uniform vec3 lightDir;     // 光照方向(单位向量)
uniform vec3 lightColor;   // 光颜色
uniform vec3 objectColor;  // 物体基础颜色void main()
{// 漫反射分量(dot 表示光与法线夹角余弦)float diff = max(dot(normalize(Normal), -lightDir), 0.0);vec3 result = diff * lightColor * objectColor;FragColor = vec4(result, 1.0);  // 输出最终颜色
})";
void LightingRenderer::initialize()
{if (isInitialized) return;          // 防止重复初始化initializeOpenGLFunctions();        // 初始化 OpenGL 函数表if (shader.isLinked()) return;// 三角形顶点(每个顶点包含位置 + 法线,共 6 个 float)GLfloat vertices[] = {// position         // normal-0.5f, -0.5f, 0.0f,  0.0f, 0.0f, 1.0f,0.5f, -0.5f, 0.0f,  0.0f, 0.0f, 1.0f,0.0f,  0.5f, 0.0f,  0.0f, 0.0f, 1.0f};// 编译并链接着色器程序shader.addShaderFromSourceCode(QOpenGLShader::Vertex, lightingVert);shader.addShaderFromSourceCode(QOpenGLShader::Fragment, lightingFrag);shader.link();shader.bind(); // 绑定以设置属性// 创建 VAO(保存所有绑定状态)vao.create();vao.bind();// 创建并填充 VBOvbo.create();vbo.bind();vbo.allocate(vertices, sizeof(vertices));// 设置属性 location 0(位置)和 location 1(法线)shader.enableAttributeArray(0);shader.setAttributeBuffer(0, GL_FLOAT, 0, 3, 6 * sizeof(float));shader.enableAttributeArray(1);shader.setAttributeBuffer(1, GL_FLOAT, 3 * sizeof(float), 3, 6 * sizeof(float));// 解绑vao.release();vbo.release();shader.release();isInitialized = true;
}
void LightingRenderer::resize(int w, int h)
{glViewport(0, 0, w, h);  // 设置 OpenGL 渲染区域width = w;height = h;
}
void LightingRenderer::render()
{glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glEnable(GL_DEPTH_TEST);  // 启用深度测试shader.bind();vao.bind();// 构造变换矩阵QMatrix4x4 model, view, proj;model.setToIdentity(); // 没有旋转缩放view.lookAt(QVector3D(0, 0, 2), QVector3D(0, 0, 0), QVector3D(0, 1, 0));proj.perspective(45.0f, float(width) / height, 0.1f, 10.0f);// 设置 uniform 变量QMatrix4x4 mvp = proj * view * model;shader.setUniformValue("u_mvp", mvp);shader.setUniformValue("u_model", model);// 动态光源方向(左右摆动)QVector3D lightDir = QVector3D(qSin(t), 0, -1).normalized();shader.setUniformValue("lightDir", lightDir);shader.setUniformValue("lightColor", QVector3D(1, 1, 1)); // 白光shader.setUniformValue("objectColor", QVector3D(1.0f, 0.5f, 0.3f)); // 橘色// 绘制三角形glDrawArrays(GL_TRIANGLES, 0, 3);vao.release();shader.release();
}
void LightingRenderer::onFrameUpdate()
{t += 0.03f;                  // 控制光源角度变化if (t > 2 * M_PI) t -= 2 * M_PI;
}
//使用
modules["光照效果"] = new LightingRenderer();
modules["光照效果"]->initialize();
if (auto* light = dynamic_cast<LightingRenderer*>(modules["光照效果"]))connect(this, &OpenGLSceneWidget::frameSwapped, light, &LightingRenderer::onFrameUpdate);

欢迎关注我,一起交流!

http://www.xdnf.cn/news/300367.html

相关文章:

  • 高性能网络优化:深入解析忙轮询(Busy Polling)技术
  • 如何把阿里云a账号下面的oss迁移到阿里云b账号下面(同区域)
  • Nginx 安全防护与 HTTPS 部署
  • UE5 把翅膀动画额外创建动画蓝图并和角色绑定混合动画
  • Kali:利用rockyou文本字典hash破解zip压缩包密码
  • MySQL + Qwen3-0.5B + Flask + Dify 工作流部署指南
  • 探秘数据中台:五大核心平台的功能全景解析
  • QuecPython+Aws:快速连接亚马逊 IoT 平台
  • 从试错到智能决策:Python与强化学习优化自动驾驶策略
  • Netty 的 Reactor 模型
  • deeplabv3+街景图片语义分割,无需训练模型,看不懂也没有影响,直接使用,cityscapes数据集_23
  • 掌握 Git 常用命令,高效管理项目版本
  • java安全入门
  • Kotlin空安全解决Android NPE问题
  • 第八章--图
  • LeetCode 3423. 循环数组中相邻元素的最大差值 题解
  • homebrew安装配置Python(MAC版)
  • Oracle01-入门
  • 个人Unity自用面经(未完)
  • 神经网络中之多类别分类:从基础到高级应用
  • ChatGPT对话导出工具-轻松提取聊天记录导出至本地[特殊字符]安装指南
  • 审计数据整合:集团多主体科目余额表合并全流程解析
  • JVM内存模型深度解剖:分代策略、元空间与GC调优实战
  • 在 Laravel 12 中实现 WebSocket 通信
  • pyqt写一个TCP(UDP)检测工具
  • 【Python】一键提取视频音频并生成MP3的完整指南 by `MoviePy`
  • 基于Jetson Nano与PyTorch的无人机实时目标跟踪系统搭建指南
  • 20250506异形拼图块(圆形、三角、正方,椭圆/半圆)的中2班幼儿偏好性测试(HTML)
  • 【ArcGISPro】属性规则--属性联动
  • 记一次ffmpeg延迟问题排查