OpenGL入门第六步:材质

目录

结果显示

材质介绍

函数解析

具体代码


结果显示

材质介绍

当描述一个表面时,我们可以分别为三个光照分量定义一个材质颜色(Material Color):环境光照(Ambient Lighting)、漫反射光照(Diffuse Lighting)和镜面光照(Specular Lighting)。通过为每个分量指定一个颜色,我们就能够对表面的颜色输出有细粒度的控制了。现在,我们再添加一个反光度(Shininess)分量,结合上述的三个颜色,我们就有了全部所需的材质属性了。

为风氏光照模型的每个分量都定义一个颜色向量。ambient材质向量定义了在环境光照下这个表面反射的是什么颜色,通常与表面的颜色相同。diffuse材质向量定义了在漫反射光照下表面的颜色。漫反射颜色(和环境光照一样)也被设置为我们期望的物体颜色。specular材质向量设置的是表面上镜面高光的颜色(或者甚至可能反映一个特定表面的颜色)。最后,shininess影响镜面高光的散射/半径。有这4个元素定义一个物体的材质,我们能够模拟很多现实世界中的材质。devernay.free.fr中的一个表格展示了一系列材质属性,它们模拟了现实世界中的真实材质。下图展示了几组现实世界的材质参数值对我们的立方体的影响:

可以看到,通过正确地指定一个物体的材质属性,我们对这个物体的感知也就不同了。效果非常明显,但是要想获得更真实的效果,我们需要以更复杂的形状替换这个立方体。

函数解析

timerEvent(QTimerEvent *event)函数

initializeGL()函数绘制光源

顶点着色器

片段着色器 

环境光通常被认为是均匀地照亮场景的,所以直接用光源的环境光和材质的环境光相乘来简单表示。

漫反射光的强度取决于光线与表面法向量的夹角。通过归一化法向量和光线方向向量,然后计算它们的点积,就能得到光线与表面的夹角余弦值。夹角越小,漫反射光越强,所以用这个点积值来控制漫反射光的强度。

镜面反射光主要是模拟物体表面的高光效果。通过计算反射方向向量和观察方向向量的点积,并对结果进行幂运算,来模拟高光的集中和锐利程度。材质的 shininess 值越大,高光就越集中和锐利。

光源的绘制和前一次(基础光照)没有区别。 

paintGL()函数:传参进行绘制

具体代码

.h

#ifndef OPENGLWIDGET_H
#define OPENGLWIDGET_H#include <QOpenGLWidget>
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>
#include <QOpenGLVertexArrayObject>
#include <QOpenGLTexture>
#include <QElapsedTimer>
#include "Camera.h"QT_BEGIN_NAMESPACE
namespace Ui { class openGLWidget; }
QT_END_NAMESPACEclass openGLWidget : public QOpenGLWidget
{Q_OBJECTpublic:openGLWidget(QWidget *parent = nullptr);~openGLWidget();
protected:virtual void timerEvent(QTimerEvent *event) override;//鼠标事件virtual void enterEvent(QEnterEvent *event) override;virtual void leaveEvent(QEvent *event) override;virtual void mouseMoveEvent(QMouseEvent *event) override;virtual void wheelEvent(QWheelEvent *event) override;virtual void keyPressEvent(QKeyEvent *event) override;virtual void keyReleaseEvent(QKeyEvent *event) override;//初始化virtual void initializeGL() override;virtual void resizeGL(int w, int h) override;virtual void paintGL() override;private:QOpenGLShaderProgram lightingShader;QOpenGLShaderProgram lightCubeShader;QOpenGLBuffer vbo;QOpenGLVertexArrayObject cubeVao;QOpenGLVertexArrayObject lightVao;QMatrix4x4 projection;QMatrix4x4 view;Camera camera {Camera(QVector3D(0.0f, 0.0f, 3.0f))};QVector3D lightPos {QVector3D(1.2f, 1.0f, 2.0f)};// 用 0 - 1 的值 直接表示颜色QVector3D diffuseColor;QVector3D ambientColor;QElapsedTimer time;float lastFrameTime {0.f};struct {bool W {false};bool S {false};bool A {false};bool D {false};} keys;private:Ui::openGLWidget *ui;
};
#endif // OPENGLWIDGET_H

.cpp

#include "openGLWidget.h"
#include "./ui_openGLWidget.h"#include <QOpenGLFunctions>
#include <QKeyEvent>
#include <QPainter>
#include <QtMath>openGLWidget::openGLWidget(QWidget *parent): QOpenGLWidget(parent), ui(new Ui::openGLWidget)
{ui->setupUi(this);setMouseTracking(true);
}openGLWidget::~openGLWidget()
{makeCurrent();lightVao.destroy();cubeVao.destroy();vbo.destroy();doneCurrent();delete ui;
}void openGLWidget::timerEvent(QTimerEvent *event)
{float s = time.elapsed() / 1000.0;float delta = s - lastFrameTime;lastFrameTime = s;if (keys.W)camera.ProcessKeyboard(FORWARD, delta);if (keys.S)camera.ProcessKeyboard(BACKWARD, delta);if (keys.A)camera.ProcessKeyboard(LEFT, delta);if (keys.D)camera.ProcessKeyboard(RIGHT, delta);view = camera.GetViewMatrix();QVector3D lightColor(qSin(lastFrameTime * 2.0), qSin(lastFrameTime * 0.7), qSin(lastFrameTime * 1.3));diffuseColor = lightColor * 0.5;ambientColor = lightColor * 0.2;update();
}void openGLWidget::enterEvent(QEnterEvent *event)
{// 隐藏鼠标指针,将指针置于窗口中心setCursor(Qt::BlankCursor);QCursor::setPos(mapToGlobal(rect().center()));
}void openGLWidget::leaveEvent(QEvent *event)
{}void openGLWidget::mouseMoveEvent(QMouseEvent *event)
{float xoffset = rect().center().x() - event->x();float yoffset = rect().center().y() - event->y();float sensitivity = 0.1f; // change this value to your likingxoffset *= sensitivity;yoffset *= sensitivity;camera.ProcessMouseMovement(xoffset, yoffset);// 将指针置于窗口中心QCursor::setPos(mapToGlobal(rect().center()));
}void openGLWidget::wheelEvent(QWheelEvent *event)
{float f = event->angleDelta().y() > 0 ? 1.0f : -1.0f;camera.ProcessMouseScroll(f);projection.setToIdentity();projection.perspective(camera.Zoom, float(width()) / float(height()), 0.1f, 100.f);
}void openGLWidget::keyPressEvent(QKeyEvent *event)
{switch(event->key()) {case Qt::Key_W:keys.W = true;break;case Qt::Key_S:keys.S = true;break;case Qt::Key_A:keys.A = true;break;case Qt::Key_D:keys.D = true;break;default:return;}
}void openGLWidget::keyReleaseEvent(QKeyEvent *event)
{switch(event->key()) {case Qt::Key_W:keys.W = false;break;case Qt::Key_S:keys.S = false;break;case Qt::Key_A:keys.A = false;break;case Qt::Key_D:keys.D = false;break;default:return;}
}void openGLWidget::initializeGL()
{// 设置用来清空屏幕的颜色 这里设置为黑色QOpenGLFunctions *f = context()->functions();f->glClearColor(0.0f, 0.0f, 0.0f, 0.0f);lightingShader.addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, R"(#version 330 corelayout (location = 0) in vec3 aPos;layout (location = 1) in vec3 aNormal;out vec3 vFragPos;out vec3 vNormal;uniform mat4 uProjection;uniform mat4 uView;uniform mat4 uModel;void main(){vFragPos = vec3(uModel * vec4(aPos, 1.0));vNormal = mat3(transpose(inverse(uModel))) * aNormal;gl_Position = uProjection * uView * uModel * vec4(aPos, 1.0);})");// 片段着色器lightingShader.addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, R"(#version 330 coreout vec4 FragColor;struct Material {vec3 ambient;vec3 diffuse;vec3 specular;float shininess;};struct Light {vec3 position;vec3 ambient;vec3 diffuse;vec3 specular;};in vec3 vNormal;in vec3 vFragPos;uniform vec3 uViewPos;uniform Material uMaterial;uniform Light uLight;void main(){// ambientvec3 ambient = uLight.ambient * uMaterial.ambient;// diffusevec3 norm = normalize(vNormal);vec3 lightDir = normalize(uLight.position - vFragPos);float diff = max(dot(norm, lightDir), 0.0);vec3 diffuse = uLight.diffuse * (diff * uMaterial.diffuse);// specularvec3 viewDir = normalize(uViewPos - vFragPos);vec3 reflectDir = reflect(-lightDir, norm);float spec = pow(max(dot(viewDir, reflectDir), 0.0), uMaterial.shininess);vec3 specular = uLight.specular * (spec * uMaterial.specular);vec3 result = ambient + diffuse + specular;FragColor = vec4(result, 1.0);})");// 编译链接if(!lightingShader.link()) {qDebug() << lightingShader.log();};//光源lightCubeShader.addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, R"(#version 330 corelayout (location = 0) in vec3 aPos;uniform mat4 uModel;uniform mat4 uView;uniform mat4 uProjection;void main(){gl_Position = uProjection * uView * uModel * vec4(aPos, 1.0);})");lightCubeShader.addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, R"(#version 330 coreout vec4 FragColor;void main(){FragColor = vec4(1.0); // set all 4 vector values to 1.0})");// 编译链接if(!lightCubeShader.link()) {qDebug() << lightCubeShader.log();};// 顶点数据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};// 创建VBOvbo.create();vbo.bind();vbo.allocate(vertices, sizeof(vertices));cubeVao.create();cubeVao.bind();lightingShader.enableAttributeArray(0);lightingShader.setAttributeBuffer(0, GL_FLOAT, 0, 3, 6 * sizeof(float));lightingShader.enableAttributeArray(1);lightingShader.setAttributeBuffer(1, GL_FLOAT, 3 * sizeof(float), 3, 6 * sizeof(float));lightVao.create();lightVao.bind();lightCubeShader.enableAttributeArray(0);lightCubeShader.setAttributeBuffer(0, GL_FLOAT, 0, 3, 6 * sizeof(float));startTimer(1);time.start();
}void openGLWidget::resizeGL(int w, int h)
{QOpenGLFunctions *f = context()->functions();f->glViewport(0, 0, w, h);projection.setToIdentity();projection.perspective(camera.Zoom, float(w) / float(h), 0.1f, 100.f);
}void openGLWidget::paintGL()
{QOpenGLFunctions* f = context()->functions();f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// 启用深度测试f->glEnable(GL_DEPTH_TEST);lightingShader.bind();lightingShader.setUniformValue("uViewPos", camera.Position);lightingShader.setUniformValue("uLight.position", lightPos);lightingShader.setUniformValue("uLight.ambient", ambientColor);lightingShader.setUniformValue("uLight.diffuse", diffuseColor);lightingShader.setUniformValue("uLight.specular", 1.0f, 1.0f, 1.0f);lightingShader.setUniformValue("uMaterial.ambient", 1.0f, 0.5f, 0.31f);lightingShader.setUniformValue("uMaterial.diffuse", 1.0f, 0.5f, 0.31f);lightingShader.setUniformValue("uMaterial.specular", 0.5f, 0.5f, 0.5f);lightingShader.setUniformValue("uMaterial.shininess", 32.0f);lightingShader.setUniformValue("uProjection", projection);lightingShader.setUniformValue("uView", view);lightingShader.setUniformValue("uModel", QMatrix4x4());cubeVao.bind();f->glDrawArrays(GL_TRIANGLES, 0, 36);lightCubeShader.bind();lightCubeShader.setUniformValue("uProjection", projection);lightCubeShader.setUniformValue("uView", view);QMatrix4x4 model;model.translate(lightPos);model.scale(0.2f);lightCubeShader.setUniformValue("uModel", model);lightVao.bind();f->glDrawArrays(GL_TRIANGLES, 0, 36);
}

Camera.h参考前一篇

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/50901.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

23.jdk源码阅读之Thread(下)

1. 写在前面 上篇文章我们介绍了Tread的一些方法的底层代码实现&#xff0c;这篇文章我们继续。 2. join()方法的底层实现 /*** Waits at most {code millis} milliseconds for this thread to* die. A timeout of {code 0} means to wait forever.** <p> This impleme…

从工艺到性能:模具3D打印材料不断革新

在模具3D打印领域&#xff0c;材料性能的持续优化与创新是推动模具3D打印的关键因素&#xff0c;近年来&#xff0c;各种3D打印新材料不断涌现&#xff0c;模具3D打印材料也开始重工艺导向逐步向性能导向发展&#xff0c;如毅速公司推出的ESU-EM191/191S及ESU-EM201不锈钢粉末、…

电脑文件误删除如何恢复?数据恢复第一步是什么?这五点要第一时间处理!

电脑文件误删除如何恢复&#xff1f;数据删除恢复的第一时间要做什么&#xff0c;你知道吗&#xff1f; 在使用电脑的过程中&#xff0c;误删除重要文件的情况时有发生。面对这种情况&#xff0c;不必过于慌张&#xff0c;因为有多种方法可以帮助你恢复误删除的文件。以下是恢复…

网络通信---UDP

前两天做了个mplayer项目&#xff0c;今日继续学习 网络内容十分重要&#xff01;&#xff01;&#xff01; 1.OSI七层模型 应用层:要传输的数据信息&#xff0c;如文件传输&#xff0c;电子邮件等&#xff08;最接近用户&#xff0c;看传输的内容类型到底是什么&#xff09; …

【数据结构与算法】顺序表

顺序表 一.顺序表的原理1.是什么2.数据结构 二.顺序表的初始化三.顺序表增加元素四.顺序表插入元素五.顺序表删除元素六.顺序表的销毁七.总结 一.顺序表的原理 1.是什么 顺序表是一种线性的结构,类似于数组,但是中间不能有空值. 元素顺序地存储在一段连续的内存空间中. 顺序表…

单关节电机动力学辨识

这是一个单关节电机的动力学辨识过程&#xff0c;这是一个yaw轴转动电机的动力学辨识过程 1、动力学建模 &#xff08;1&#xff09;整体动力学 F J α f F J\alpha f FJαf 单关节的物理量包括惯性项、离心力和科氏力、摩擦力。这里忽略离心力和科氏力&#xff0c;据说…

SolidEdge二次开发(C#)-环境配置

文章目录 1、前言2、环境配置2.1 安装Solidworks20242.2 安装VS20222.3 查看Com组件2.3.1 在VS2022中创建一个wpf工程项目2.3.2 添加com组件 1、前言 SolidEdge是Siemens PLM Software公司旗下的三维CAD软件&#xff0c;采用Siemens PLM Software公司自己拥有专利的Parasolid作…

js动画插件-vue

分享一个动画插件 学习 动画插件 是进入大厂的必备技能 首先我们需要先学会 去使用js 动画 封装好的 GreenSock 动画平台 &#xff08;GSAP&#xff09; greensock.com/gsap/ 就是这个插件 我现在分享一个用例 其实很简单 但是 具体的属性 和很多 内容需要慢慢使用 慢慢看…

C++客户端Qt开发——系统相关(文件操作)

2.文件操作 ①输入输出设备类 在Qt中&#xff0c;文件读写的类为QFile。QFile的父类为QFileDevice,QFileDevice提供了文件交互操作的底层功能。QFileDevice的父类是QIODevice,QIODevice的父类为QObject。 QIODevice是Qt中所有输入输出设备(input/output device,简称I/O设备)…

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 环形字符串最长子串(200分) - 三语言AC题解(Python/Java/Cpp)

🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 🍿 最新华为OD机试D卷目录,全、新、准,题目覆盖率达 95% 以上,支持题目在线…

【React】useState:状态管理的基石

文章目录 一、什么是 useState&#xff1f;二、useState 的基本用法三、useState 的工作原理四、高级用法五、最佳实践 在现代前端开发中&#xff0c;React 是一个非常流行的库&#xff0c;而 useState 是 React 中最重要的 Hook 之一。useState 使得函数组件能够拥有自己的状态…

深入理解synchronized(简记)

深入理解synchronized 管程synchronized对象的内存布局锁状态记录锁对象状态转换偏向锁轻量级锁锁对象转换总结 管程synchronized Java 参考了 MESA 模型&#xff0c;语言内置的管程&#xff08;synchronized&#xff09;对 MESA 模型进行了精简。 对象的内存布局 对象头 Mar…

Nginx笔记(一)

一、Nginx简介 Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器 [13]&#xff0c;同时也提供了IMAP/POP3/SMTP服务。Nginx是由伊戈尔赛索耶夫为俄罗斯访问量第二的Rambler.ru站点&#xff08;俄文&#xff1a;Рамблер&#xff09;开发的&#xff0c;公开版本1.…

如何在宝塔面板给域名配置 SSL 证书

首先需要有证书 这里以阿里云为例 1. 首先进入到 SSL 证书管理控制台 选择个人测试证书&#xff0c;并点击购买 免费的可以使用三个月。 购买完成之后回到控制台。 点击创建证书&#xff0c;将标红的地方填写&#xff0c;其他默认就好。 然后提交审核就行。 这里需要对域名…

【React】组件:全面解析现代前端开发的基石

文章目录 一、什么是组件&#xff1f;二、组件的类型三、组件的生命周期四、状态管理五、属性传递六、组合与继承七、最佳实践 在现代前端开发中&#xff0c;React 已成为开发者构建用户界面的首选框架之一。React 的强大之处在于其组件化设计&#xff0c;允许开发者将 UI 拆分…

Wireshark自定义协议解析器插件C语言开发二

接着上一篇安装文章&#xff0c;在wireshark插件开发完成后&#xff0c;仿真的dll并不能直接分享使用&#xff0c;当另外电脑缺少必要的c环境或依赖项时候&#xff0c;在打开wireshark软件时候即会报错。 上图是仿真得到的dll文件路径&#xff0c;但是并不能在其他没有安装了v…

linux驱动--中断

中断号和中断的申请 中断号的添加-----定义设备节点&#xff0c;描述当前设备 通过设备树文件获取 /dts/xxxx.dts文件中进行设备的设置 在dts设备树文件中进行设备的定义&#xff0c;包括继承的设备&#xff0c;中断号的设置 需要对我们的dts设备树文件进行编译&#xff0…

天机学堂第二天项目 添加我的课表 项目总结

目录 根据产品原型得到数据库表结构 RabbitMq监听 构造器注入 幂等 mybatisplus 分页查询的多种写法 在new page里面添加排序 查询条件中 用orderBydESC指定排序 ​编辑 链式编程中使用page指定排序 stream流 ​编辑 在网关中解析token 根据产品原型得到数据库表结构 根…

基于物联网的区块链算力网络,IGP/BGP协议

目录 基于物联网的区块链算力网络 IGP/BGP协议 IGP(内部网关协议) BGP(边界网关协议) 内部使用ISP的外部使用BGP的原因 一、网络规模和复杂性 二、路由协议的特性 三、满足业务需求 四、结论 基于物联网的区块链算力网络 通 过 多个物联网传感器将本地计算…