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

qt + opengl 给立方体增加阴影

在前几篇文章里面学会了通过opengl实现一个立方体,那么这篇我们来学习光照。

风氏光照模型的主要结构由3个分量组成:环境(Ambient)、漫反射(Diffuse)和镜面(Specular)光照。下面这张图展示了这些光照分量看起来的样子:

1 环境光照(Ambient Lighting):即使在黑暗的情况下,世界上通常也仍然有一些光亮(月亮、远处的光),所以物体几乎永远不会是完全黑暗的。为了模拟这个,我们会使用一个环境光照常量,它永远会给物体一些颜色。

2 漫反射光照(Diffuse Lighting):模拟光源对物体的方向性影响(Directional Impact)。它是风氏光照模型中视觉上最显著的分量。物体的某一部分越是正对着光源,它就会越亮。

3 镜面光照(Specular Lighting):模拟有光泽物体上面出现的亮点。镜面光照的颜色相比于物体的颜色会更倾向于光的颜色。

我们运行下结果如下:

1 我们设置顶点着色器

#version 330 core
//顶点着色器uniform mat4 mvp_matrix;
uniform mat4 model_matrix;layout (location = 0) in vec3 a_position;   //空间坐标
layout (location = 1) in vec3 aColor;   //颜色
layout (location = 2) in vec2 a_texcoord; //纹理out vec3 FragPos;
out vec2 outtexcoord;
out vec3 outclolor;
uniform  mat4 model;
uniform  mat4 view;
uniform  mat4 projection;
out vec3 Normal;void main()
{gl_Position =  projection*view* model * vec4(a_position, 1.0);outtexcoord = a_texcoord;outclolor = aColor; 
}

在设置片段着色器

#version 330 core
//像素着色器
in vec2 outtexcoord;
in vec3 outclolor;
out vec4 FragColor;
in vec3 FragPos;
in vec3 Normal;
uniform vec3 lightPos;
uniform vec3 viewPos;
uniform vec3 lightColor;
uniform vec3 objectColor;
uniform sampler2D texture;void main()
{//ambient 环境光照float ambientStrength = 0.1; //环境因子vec3 ambient = ambientStrength * lightColor;//环境因子*光照颜色vec3 result = ambient * objectColor;//环境因子*光照位置*物体颜色FragColor = vec4(result, 1.0);}

上立方体代码

#include "widget.h"
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>
#include <QMouseEvent>
#include <QDateTime>
#include <QtMath>
#include "ui_widget.h"#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>
#include <QMouseEvent>//GLfloat light_ambient[4]={0.5, 0.5, 0.5, 1.0};
//GLfloat light_diffuse[4]={1.0, 1.0, 1.0, 1.0};
//GLfloat light_position[4]={0.0, 0.0, 2.0, 0.0};GLfloat LightAmbient[4] = {0.5f, 0.5f, 0.5f, 1.0f};  //环境光参数
GLfloat LightDiffuse[4] = {1.0f, 1.0f, 1.0f, 1.0f};  //漫散光参数
GLfloat LightPosition[4] = {0.0f, 0.0f, 2.0f, 1.0f}; //光源位置
//模型主动刷新帧率
#define ACTION_FPS  60
#define LIGHT_COLOR QVector3D(1.2f, 1.0f, 2.0f)
#define EYE_CENTER  QVector3D(0.0, 0.0, 3.0)
#define LIGHT_POS   QVector3D(2.5f, 2.0f, -1.0f)static const char *vertexShaderSource ="#version 330\n""layout (location = 0) in vec4 vertex;\n""layout (location = 1) in vec4 texCoord;\n""out vec4 texc;\n""out vec3 ourColor;\n""uniform  mat4 model;\n""void main(void)\n""{\n""    gl_Position = model * vertex;\n""    texc = texCoord;\n""}\n";static const char *fragmentShaderSource ="#version 330\n""uniform sampler2D texture;\n""in vec3 ourColor;\n""in vec4 texc;\n""void main(void)\n""{\n""    gl_FragColor = texture2D(texture, texc.st)* vec4(1.0f, 0.5f, 0.5f, 1.0);\n""}\n";static const char *vertex1ShaderSource ="#version 330\n""layout (location = 0) in vec4 aPos;\n""layout (location = 1) in vec4 aColor;\n""uniform mat4 model;\n""uniform mat4 view;\n""uniform mat4 projection;\n""out vec4 FragPos;\n""out vec4 Normal;\n""void main(void)\n""{\n"//"    FragPos = vec3(model * vec4(aPos, 1.0));\n"// "    Normal = mat3(transpose(inverse(model))) * aNormal;\n""    gl_Position = projection * view * model * aPos;\n""}\n";
static const char *vertex2ShaderSource ="#version 330\n""layout (location = 0) in vec4 aPos;\n""out vec3 result;\n""uniform mat4 model;\n""uniform mat4 view;\n""uniform mat4 projection;\n""uniform vec3 objectColor;\n""uniform vec3 lightColor;\n""uniform float ambientStrength;\n""void main(void)\n""{\n""   gl_Position = projection * view * model * aPos;\n""   vec3 ambient = ambientStrength * lightColor;\n""   result = ( ambient   ) * objectColor;\n""}\n";
static const char *fragment1ShaderSource ="#version 330\n""in vec3 FragPos;\n""in vec3 Normal;\n""uniform vec3 lightPos;\n""uniform vec3 viewPos;\n""uniform vec3 objectColor;\n""uniform vec3 lightColor;\n""void main(void)\n""{\n"// ambient" float ambientStrength = 0.1;\n"" vec3 ambient = ambientStrength * lightColor;\n"// diffuse" vec3 norm = normalize(Normal);\n"" vec3 lightDir = normalize(lightPos - FragPos);\n"" float diff = max(dot(norm, lightDir), 0.0);\n"" vec3 diffuse = diff * lightColor; \n"// specular" float specularStrength = 0.5;\n"" vec3 viewDir = normalize(viewPos - FragPos);\n"" vec3 reflectDir = reflect(-lightDir, norm);\n"" float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);\n"" vec3 specular = specularStrength * spec * lightColor;\n"" vec3 result = (ambient + diffuse + specular) * objectColor;\n"" gl_FragColor = vec4(result, 1.0);\n""}\n";
static const char *vertexLight1Source ="#version 330\n""layout (location = 0) in vec4 aPos;\n""layout (location = 1) in vec4 aColor;\n""uniform mat4 matrix;\n""uniform mat4 view;\n""uniform mat4 projection;\n""void main(void)\n""{\n""    gl_Position =   projection * view * matrix * aPos;\n""}\n";//       " gl_FragColor = texture2D(texture, texc.st) *vec4(1.0f, 0.5f, 0.5f, 1.0);\n"
static const char *fragmentLight1Source ="#version 330\n""out vec4 FragColor;\n""void main(void)\n""{\n""FragColor = vec4(1.0);\n""}\n";//static const char *vertexLightSource =
//    "#version 330\n"
//    "layout (location = 0) in vec4 aPos;\n"
//    "layout (location = 1) in vec4 aTexCord;\n"
//    "uniform mat4 matrix;\n"
//    "uniform mat4 view;\n"
//    "uniform mat4 projection;\n"
//    "out vec4 texc;\n"
//    "void main(void)\n"
//    "{\n"
//    "    gl_Position =   projection * view * matrix * aPos;\n"
//        " texc = aTexCord;\n"
//    "}\n";" gl_FragColor = texture2D(texture, texc.st) *vec4(1.0f, 0.5f, 0.5f, 1.0);\n"
//static const char *fragmentLightSource =
//      "#version 330\n"
//      "out vec4 FragColor;\n"
//       "uniform sampler2D texture;\n"
//      "in vec4 texc;\n"
//      "uniform vec3 objectColor;\n"
//      "uniform vec3 lightColor;\n"
//      "void main(void)\n"
//      "{\n"
//        "gl_FragColor = vec4(lightColor * objectColor, 1.0);\n"
//      "}\n";Widget::Widget():QOpenGLWidget(),m_xRos(0),m_yRos(0)
{cam = QVector3D(m_xRos, m_yRos, m_zRos);cameraPos = QVector3D(0, 0, 3);timer = new QTimer;timer->setInterval(20);connect(timer,&QTimer::timeout,this,[=]{qDebug()<<"timeout";//       m_xRos+=30;//       m_yRos+=30;//rotateBy(2 * 16, +2 * 16, -1 * 16);rotateBy(10 * 16, +10 * 16, -1 * 16);});timer->start();
}
Widget::~Widget()
{makeCurrent();vbo.destroy();for (int i = 0; i < 6; ++i)delete textures[i];delete program;doneCurrent();
}QSize Widget::minimumSizeHint() const
{return QSize(400, 400);
}QSize Widget::sizeHint() const
{return QSize(400, 400);
}void Widget::rotateBy(int xAngle, int yAngle, int zAngle)
{xRot += xAngle;yRot += yAngle;zRot += zAngle;update();timer->stop();
}void Widget::setClearColor(const QColor &color)
{clearColor = color;update();
}void Widget::initializeGL()
{/*vertices = {// ---- 位置----   - 纹理坐标 -      ---- 颜色 ----0.5f, -0.5f, -0.5f,   1.0f, 1.0f, 1.0f, 0.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, 0.0f, 0.0f, 0.0f, 1.0f,0.5f, 0.5f, -0.5f,    1.0f, 0.0f, 1.0f, 1.0f, 0.0f,0.5f, 0.5f, -0.5f,   1.0f, 1.0f, 1.0f, 0.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, 0.0f, 0.0f, 0.0f, 1.0f,0.5f, 0.5f, 0.5f,    1.0f, 0.0f, 1.0f, 1.0f, 0.0f,0.5f, -0.5f, 0.5f,   1.0f, 1.0f, 1.0f, 0.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, 0.0f, 0.0f, 0.0f, 1.0f,0.5f, 0.5f, 0.5f,    1.0f, 0.0f, 1.0f, 1.0f, 0.0f,-0.5f, -0.5f, -0.5f,  1.0f, 1.0f, 1.0f, 0.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, 0.0f, 0.0f, 0.0f, 1.0f,-0.5f, 0.5f, -0.5f,   1.0f, 0.0f, 1.0f, 1.0f, 0.0f,0.5f, -0.5f, 0.5f,   1.0f, 1.0f, 1.0f, 0.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, 0.0f, 0.0f, 0.0f, 1.0f,0.5f, -0.5f, -0.5f,  1.0f, 0.0f, 1.0f, 1.0f, 0.0f,-0.5f, -0.5f, 0.5f,   1.0f, 1.0f, 1.0f, 0.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, 0.0f, 0.0f, 0.0f, 1.0f,-0.5f, 0.5f, 0.5f,    1.0f, 0.0f, 1.0f, 1.0f, 0.0f,};*/vertices = {// ---- 位置----   - 纹理坐标 -      ---- 颜色 ----0.5f, -0.5f, -0.5f,  1.0f, 1.0f, 1.0f,        1.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, 0.0f, 0.0f,        0.0f, 0.0f,0.5f, 0.5f, -0.5f,   1.0f, 0.0f, 1.0f,        1.0f, 0.0f,//10.5f, 0.5f, -0.5f,   1.0f, 1.0f, 1.0f,        1.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, 0.0f, 0.0f,        0.0f, 0.0f,0.5f, 0.5f, 0.5f,    1.0f, 0.0f, 1.0f,        1.0f, 0.0f,//20.5f, -0.5f, 0.5f,   1.0f, 1.0f, 1.0f,          1.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, 0.0f, 0.0f,          0.0f, 0.0f,0.5f, 0.5f, 0.5f,    1.0f, 0.0f, 1.0f,          1.0f, 0.0f,//3-0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f,         1.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, 0.0f, 0.0f,         0.0f, 0.0f,-0.5f, 0.5f, -0.5f,  1.0f, 0.0f, 1.0f,         1.0f, 0.0f,//40.5f, -0.5f, 0.5f,     1.0f, 1.0f, 1.0f,       1.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, 0.0f, 0.0f,         0.0f, 0.0f,0.5f, -0.5f, -0.5f,   1.0f, 0.0f, 1.0f,        1.0f, 0.0f,//5-0.5f, -0.5f, 0.5f,1.0f,   1.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, 0.0f, 0.0f,      0.0f,-0.5f, 0.5f, 0.5f, 1.0f,   1.0f, 0.0f, 1.0f,      0.0f,};GLushort indices[36] ={/*** 每两个三角形渲染一个面* 注意节点顺序,因为开启了遮挡剔除(glEnable(GL_CULL_FACE)),opengl是根据顶点顺序决定三角形法线方向的,顺时针顺序算出来* 三角形是朝里的就不画了,所以 0 3 1 会导致该三角形不显示,后面的三角形同样的道理注意顶点顺序*///Face 00,  1 , 3, //triangle12,  0,  3, //triangle2//Face 14,  5,  7, //triangle36,  4,  7, //triangle4//Face 28,  9,  11, //triangle510,  8,  11, //triangle6//Face 312,  13,  15, //triangle714,  12,  15, //triangle8//Face 416,  17,  19, //triangle918,  16,  19, //triangle10//Face 520,  21,  23, //triangle1122,  20,  23, //triangle12};initializeOpenGLFunctions();// makeObject();//#define PROGRAM_VERTEX_ATTRIBUTE 0//#define PROGRAM_TEXCOORD_ATTRIBUTE 1//    lightinhProgram = new QOpenGLShaderProgram;
//    lightinhProgram->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/Diffuse.vs");
//    lightinhProgram->addShaderFromSourceFile(QOpenGLShader::Fragment,":/Diffuse.fs");
//    lightinhProgram->link();
//    lightinhProgram->bind();//激活Program对象program = new QOpenGLShaderProgram;program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shader.vs");program->addShaderFromSourceFile(QOpenGLShader::Fragment,":/shader.fs");program->link();program->bind();//激活Program对象vbo.create();vbo.bind();              //绑定到当前的OpenGL上下文,vbo.allocate(vertices.constData(), vertices.count() * sizeof(GLfloat));//初始化VAO,设置顶点数据状态(顶点,法线,纹理坐标等)vao.create();vao.bind();//    indexBuf.create();
//    indexBuf.bind();
//    indexBuf.allocate(indices, 36 * sizeof(GLushort));for (int j = 0; j < 6; ++j){textures[j] = new QOpenGLTexture(QImage(QString(":/cube%1.png").arg(j+1)).mirrored());textures[j]->setMinMagFilters(QOpenGLTexture::LinearMipMapLinear,QOpenGLTexture::Linear);textures[j]->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::ClampToEdge);textures[j]->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::ClampToEdge);}program->setAttributeBuffer(0, GL_FLOAT, 0,                  3, 8 * sizeof(float));   //设置aPos顶点属性program->setAttributeBuffer(1, GL_FLOAT, 3 * sizeof(float),  3, 8 * sizeof(float));   //设置aColor顶点颜色program->setAttributeBuffer(2, GL_FLOAT, 6 * sizeof(float),  2, 8 * sizeof(float));   //设置aColor顶点颜色program->enableAttributeArray(0); //使能aPos顶点属性program->enableAttributeArray(1); //使能aColor顶点颜色program->enableAttributeArray(2); //使能aColor顶点颜色program->setUniformValue("texture", 0);//    lightinhProgram->setAttributeBuffer(0, GL_FLOAT, 0,                  3, 8 * sizeof(float));   //设置aPos顶点属性
//    lightinhProgram->enableAttributeArray(0); //使能aPos顶点属性projection.setToIdentity();projection.perspective(45,(float)width()/height(),2.0,45.0);//构建透视矩阵,这个可以是固定写法//projection.perspective(45,(float)width()/height(),0.1,100);//构建透视矩阵,这个可以是固定写法program->setUniformValue("projection", projection);//program1->setUniformValue("projection", projection);//program->setUniformValue("texture", 0);//    vao.release();//    vbo.release();
}void Widget::paintGL()
{glClearColor(0.1f, 0.1f, 0.1f, 1.0f);  //设置清屏颜色// glClearColor(0.1f,0.5f,0.7f,1.0f);  //设置清屏颜色glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//开启深度测试glEnable(GL_DEPTH_TEST);//开启遮挡剔除glEnable(GL_CULL_FACE);QMatrix4x4 m;m.translate(0.0f, 0.0f, 0.0f);m.rotate(xRot / 16.0f, 1.0f, 0.0f, 0.0f);m.rotate(yRot / 16.0f, 0.0f, 1.0f, 0.0f);m.rotate(zRot / 16.0f, 0.0f, 0.0f, 1.0f);m.scale(0.5);QMatrix4x4 modelmatrix;//平移至左下角modelmatrix.translate(0.0f, 0.0f, 0.0f);//鼠标滚动旋转角度modelmatrix.rotate(xRot / 16.0f, 1.0f, 0.0f, 0.0f);modelmatrix.rotate(yRot / 16.0f, 0.0f, 1.0f, 0.0f);modelmatrix.rotate(zRot / 16.0f, 0.0f, 0.0f, 1.0f);//滚轮缩放modelmatrix.scale(0.5);program->setUniformValue("model", modelmatrix);QMatrix4x4 view;view.lookAt(EYE_CENTER, QVector3D(0, 0, -20), QVector3D(0, 1, 0));program->setUniformValue("view", view);program->setUniformValue("lightColor", QVector3D(1.0f, 1.0f, 1.0f));//灯光颜色program->setUniformValue("objectColor", QVector3D(1.0f, 0.5f, 0.3f));//物体颜色for (int i = 0; i < 6; ++i) {textures[i]->bind();glDrawArrays(GL_TRIANGLE_FAN, i * 4, 4);}
}
void Widget::resizeGL(int width, int height)
{this->glViewport(0,0,width,height);                //定义视口区域
}void Widget::mousePressEvent(QMouseEvent *event)
{lastPos = event->pos();
}void Widget::mouseMoveEvent(QMouseEvent *event)
{int dx = event->x() - lastPos.x();int dy = event->y() - lastPos.y();if (event->buttons() & Qt::LeftButton) {rotateBy(8 * dy, 8 * dx, 0);} else if (event->buttons() & Qt::RightButton) {rotateBy(8 * dy, 0, 8 * dx);}lastPos = event->pos();
}void Widget::mouseReleaseEvent(QMouseEvent * /* event */)
{// emit clicked();
}
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>#include <QOpenGLWidget>
#include <QOpenGLExtraFunctions>
#include <QOpenGLBuffer>
#include <QOpenGLShaderProgram>
#include <QOpenGLVertexArrayObject>
#include <QTimer>
#include <QOpenGLTexture>
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QOpenGLBuffer>
#include <QOpenGLVertexArrayObject>
#include <QTimer>namespace Ui {
class Widget;
}QT_FORWARD_DECLARE_CLASS(QOpenGLShaderProgram);
QT_FORWARD_DECLARE_CLASS(QOpenGLTexture)class Widget : public QOpenGLWidget, protected QOpenGLFunctions
{Q_OBJECTpublic://using QOpenGLWidget::QOpenGLWidget;Widget();~Widget();QSize minimumSizeHint() const override;QSize sizeHint() const override;void rotateBy(int xAngle, int yAngle, int zAngle);void setClearColor(const QColor &color);void drawLight();signals:// void clicked();protected:void initializeGL() override;void paintGL() override;void resizeGL(int width, int height) override;void mousePressEvent(QMouseEvent *event) override;void mouseMoveEvent(QMouseEvent *event) override;void mouseReleaseEvent(QMouseEvent *event) override;private:Ui::Widget *ui;QColor clearColor = Qt::black;QPoint lastPos;int xRot = 0;int yRot = 0;int zRot = 0;QOpenGLTexture *textures[6] = {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr};QOpenGLShaderProgram *program = nullptr;QOpenGLShaderProgram *lightinhProgram = nullptr;QOpenGLBuffer vbo;QVector<float> vertices;QOpenGLVertexArrayObject vao;QOpenGLVertexArrayObject vao1;QTimer* timer;float m_xRos = 0.0f;float m_yRos = 0.0f;float m_zRos = 3.0f;QVector3D   cam;int nCount=0;QVector3D cameraPos;QVector3D cameraTarget;QVector3D cameraDirection;float     m_viewAngle=0.0f;float     radius = 10.0f;float     camX= 10.0f;float     camZ= 10.0f;QVector3D _cameraPos = {0.0f, 0.0f, 3.0f};QVector3D _cameraFront = {0.0f, 0.0f, -1.0f};QVector3D _cameraUp = {0.0f, 1.0f, 0.0f};float ambientStrength = 0.0;//关照强度QMatrix4x4 projection;QOpenGLTexture *texture;QOpenGLBuffer indexBuf;
};#endif // WIDGET_H

运行下结果如下:

我们可以看到物体并全黑,还是可以看到物体的轮廓,为什么变黑呢?变黑的原因:1.无光源2无

 法线。

二 漫反射

环境光照本身不能提供最有趣的结果,但是漫反射光照就能开始对物体产生显著的视觉影响了。漫反射光照使物体上与光线方向越接近的片段能从光源处获得更多的亮度。为了能够更好的理解漫反射光照,请看下图:

图左上方有一个光源,它所发出的光线落在物体的一个片段上。我们需要测量这个光线是以什么角度接触到这个片段的。如果光线垂直于物体表面,这束光对物体的影响会最大化(更亮)。为了测量光线和片段的角度,我们使用一个叫做法向量(Normal Vector)的东西,它是垂直于片段表面的一个向量(这里以黄色箭头表示),我们在后面再讲这个东西。这两个向量之间的角度很容易就能够通过点乘计算出来。

法向量是一个垂直于顶点表面的(单位)向量。由于顶点本身并没有表面(它只是空间中一个独立的点),我们利用它周围的顶点来计算出这个顶点的表面。我们能够使用一个小技巧,使用叉乘对立方体所有的顶点计算法向量,但是由于3D立方体不是一个复杂的形状,所以我们可以简单地把法线数据手工添加到顶点数据中。更新后的顶点数据数组可以在这里找到。试着去想象一下,这些法向量真的是垂直于立方体各个平面的表面的(一个立方体由6个平面组成)。

(修改顶点着色器)

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;out vec3 Normal;
out vec3 FragPos;
out vec4 OutTextcord;void main()
{gl_Position = projection * view * model * vec4(aPos, 1.0);FragPos = vec3(model*vec4(aPos,1.0));Normal = mat3(transpose(inverse(model))) * aNormal;}

修改片段着色器

#version 330 coreout vec4 FragColor;in vec3 Normal;
in vec3 FragPos;
in vec4 OutTextcord;uniform vec3 viewPos;
uniform vec3 lightPos;
uniform vec3 lightColor;
uniform vec3 objectColor;
uniform sampler2D texture;void main()
{float ambientStrength = 0.1;vec3 ambient = ambientStrength * lightColor;// diffusevec3 norm = normalize(Normal);vec3 lightDir = normalize(lightPos - FragPos);float diff = max(dot(norm, lightDir), 0.0);vec3 diffuse = diff * lightColor;// specularfloat specularStrength = 0.5;vec3 viewDir = normalize(viewPos - FragPos);vec3 reflectDir = reflect(-lightDir, norm);float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);vec3 specular = specularStrength * spec * lightColor;vec3 result = (ambient + diffuse + specular) * objectColor;FragColor = vec4(result, 1.0);}
#include "testshadewidget.h"
#define EYE_CENTER  QVector3D(0.0, 0.0, 3.0)testshadeWidget::testshadeWidget():QOpenGLWidget(),m_xRos(0),m_yRos(0),m_zRos(0),lightPos(1.0, 1.0, 0.0),m_verticalAngle(45)
{cam = QVector3D(m_xRos, m_yRos, m_zRos);cameraPos = QVector3D(0, 0, 3);timer = new QTimer;timer->setInterval(100);connect(timer,&QTimer::timeout,this,[=]{qDebug()<<"timeout";//       m_xRos+=30;//       m_yRos+=30;//rotateBy(2 * 16, +2 * 16, -1 * 16);/*if(nDerection==0) //RIGHT{m_xRos  +=  0.05f;m_yRos  =  0;m_zRos  =  0;if(m_xRos>=1.0f){m_xRos = 0.0f;timer->stop();}}else if(nDerection==1)//LEFT{m_xRos  -=  0.05f;m_yRos  =  0;m_zRos  =  0;if(m_xRos<=-1.0f){m_xRos = 0.0f;timer->stop();}}else if(nDerection==2)//DOWN{m_xRos  =  0;m_yRos  -=  0.05f;m_zRos  =  0;if(m_yRos<=-1.0f){m_yRos = 0.0f;timer->stop();}}else if(nDerection==3)//UP{m_xRos  =  0;m_yRos  +=  0.05f;m_zRos  =  0;if(m_yRos>=1.0f){m_yRos = 0.0f;timer->stop();}}update();// offsetBy(10 * 16, +10 * 16, -1 * 16);*/rotateBy(10 * 16, +10 * 16, -1 * 16);});timer->start();
}testshadeWidget::~testshadeWidget()
{}void testshadeWidget::initializeGL()
{float vertices22[] = {   // ---- 顶点 ----           - 法向量 -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,//1 正面  -z垂直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,//2上面  垂直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,//3右边 x-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,//4 左边 -x0.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,//5 后面  z-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,//6下面-y};float vertices11[] = {// ---- 顶点 ----        - 法向量 -// ---- 顶点 ----        - 法向量 -                                  - 纹理 -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,                      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,       //1 正面  -z垂直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,                       1.0f,0.0f,0.5f, 0.5f, 0.5f,           0.0f, 1.0f, 0.0f,                       1.0f,1.0f,       //2上面  垂直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,                      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,                 //3右边 x-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,                    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,        //4 左边 -x0.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,                    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,   //5 后面  z-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,                  1.0f,0.0f,-0.5f, 0.5f, 0.5f,          0.0f, -1.0f, 0.0f,                  1.0f,1.0f,      //6下面-y};vertices = {// ---- 位置----   - 纹理坐标 -      ---- 颜色 ----0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f,   1.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, 0.0f, 0.0f,   0.0f, 0.0f,0.5f, 0.5f, -0.5f,   1.0f, 0.0f, 1.0f,   1.0f, 0.0f,//10.5f, 0.5f, -0.5f,   1.0f, 1.0f, 1.0f,   1.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, 0.0f, 0.0f,   0.0f, 0.0f,0.5f, 0.5f, 0.5f,    1.0f, 0.0f, 1.0f,   1.0f, 0.0f,//20.5f, -0.5f, 0.5f,  1.0f, 1.0f, 1.0f,    1.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, 0.0f, 0.0f,    0.0f, 0.0f,0.5f, 0.5f, 0.5f,   1.0f, 0.0f, 1.0f,    1.0f, 0.0f,//3-0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f,   1.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, 0.0f, 0.0f,   0.0f, 0.0f,-0.5f, 0.5f, -0.5f,  1.0f, 0.0f, 1.0f,   1.0f, 0.0f,//40.5f, -0.5f, 0.5f,    1.0f, 1.0f, 1.0f, 1.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, 0.0f, 0.0f, 0.0f, 0.0f,0.5f, -0.5f, -0.5f,  1.0f, 0.0f, 1.0f, 1.0f, 0.0f,//5-0.5f, -0.5f, 0.5f,    1.0f, 1.0f, 1.0f, 1.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, 0.0f, 0.0f, 0.0f, 0.0f,-0.5f, 0.5f, 0.5f,     1.0f, 0.0f, 1.0f, 1.0f, 0.0f,//6};//绑定OpenGL函数指针?类似GLAD库的作用?initializeOpenGLFunctions();//开启深度测试glEnable(GL_DEPTH_TEST);lightprogram = new QOpenGLShaderProgram;lightprogram->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/base_lighting.vs");lightprogram->addShaderFromSourceFile(QOpenGLShader::Fragment,":/base_lighting.fs");lightprogram->link();lightprogram->bind();//激活Program对象program = new QOpenGLShaderProgram;
//    program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shader.vs");
//    program->addShaderFromSourceFile(QOpenGLShader::Fragment,":/shader.fs");program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/Diffuse.vs");program->addShaderFromSourceFile(QOpenGLShader::Fragment,":/Diffuse.fs");program->link();program->bind();//激活Program对象unsigned int indices[] = {0, 1, 3, // first triangle1, 2, 3  // second triangle};vbo.create();vbo.bind();              //绑定到当前的OpenGL上下文,vbo.setUsagePattern(QOpenGLBuffer::StaticDraw);vbo.allocate(vertices22, sizeof(vertices22));//vbo.allocate(vertices.constData(), vertices.count() * sizeof(GLfloat));vao.create();vao.bind();//    _ebo = new QOpenGLBuffer(QOpenGLBuffer::IndexBuffer);
//    _ebo->create();
//    if(!_ebo->bind()){
//        qDebug() << "ebo绑定失败!";
//    }
//    _ebo->allocate(indices, sizeof(indices));for (int j = 0; j < 6; ++j){textures[j] = new QOpenGLTexture(QImage(QString(":/cube%1.png").arg(j+1)).mirrored());textures[j]->setMinMagFilters(QOpenGLTexture::LinearMipMapLinear,QOpenGLTexture::Linear);textures[j]->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::ClampToEdge);textures[j]->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::ClampToEdge);}program->setAttributeBuffer(0, GL_FLOAT, 0,                  3, 6 * sizeof(float));   //设置aPos顶点属性program->setAttributeBuffer(1, GL_FLOAT, 3 * sizeof(float),  3, 6 * sizeof(float));   //设置aColor顶点颜色// program->setAttributeBuffer(2, GL_FLOAT, 6 * sizeof(float),  2, 8 * sizeof(float));   //设置aColor顶点颜色program->enableAttributeArray(0); //使能aPos顶点属性program->enableAttributeArray(1); //使能aColor顶点颜色// program->enableAttributeArray(2); //使能aColor顶点颜色//program->setUniformValue("texture", 0);lightVao.create();lightVao.bind();lightprogram->setAttributeBuffer(0, GL_FLOAT, 0, 3, 6 * sizeof(float));lightprogram->enableAttributeArray(0);   // 使能 location = 0的顶点属性aPos
}
void testshadeWidget::rotateBy(int xAngle, int yAngle, int zAngle)
{xRot += xAngle;yRot += yAngle;zRot += zAngle;update();//timer->stop();
}void testshadeWidget::offsetBy(int xPos, int yPos, int zPos)
{m_xRos += xPos;m_yRos += yPos;m_zRos += zPos;update();
}void testshadeWidget::mouseMoveEvent(QMouseEvent *event)
{
//    if(event->x() == m_cursorPos.x() && m_cursorPos.y() == event->y())
//        return;//    QPoint MovePos = QCursor::pos();
//    QPoint currentPos = mapFromGlobal(MovePos);
//    int xoffset = 0;
//    int yoffset = 0;
//    xoffset  =  currentPos.x() - m_cursorPos.x();
//    yoffset  =  currentPos.y() - m_cursorPos.y();//    qDebug()<<"1111111111"<<m_xRos;
//    if(xoffset>0 )
//    {
//       m_xRos += 0.1;
//       m_yRos = 0;
//       if(m_xRos>=1.0f)
//       {
//           m_xRos = 0.0f;
//           m_yRos = 0.0f;
//       }
//    }
//    else if(xoffset<0 )
//    {
//       m_xRos -= 0.1;
//       m_yRos = 0;
//       if(m_xRos<=-1.0f)
//       {
//           m_xRos = 0.0f;
//           m_yRos = 0.0f;
//       }
//    }
//    else if(yoffset>0)
//    {
//       m_xRos = 0;
//       m_yRos -= 0.1;
//       if(m_yRos<=-1.0f)
//       {
//           m_xRos = 0.0f;
//           m_yRos = 0.0f;
//       }
//    }
//    else if(yoffset<0)
//    {
//       m_xRos = 0;
//       m_yRos += 0.1;
//       if(m_yRos>=1.0f)
//       {
//           m_xRos = 0.0f;
//           m_yRos = 0.0f;
//       }
//    }
//    update();
//    m_cursorPos = currentPos;//timer->start();//m_yRos += yPos;//update();//m_yRos += yoffset;//qDebug()<<"mouseMoveEvent"<<xoffset<<yoffset<<m_xRos<<m_yRos<<xPos<<yPos;//qDebug()<<"m_cursorPos"<<(m_xRos==1.0);//m_cursorPos = QPoint(event->x(),event->y());}void testshadeWidget::mouseReleaseEvent(QMouseEvent *event)
{if(event->x() == m_cursorPos.x() && m_cursorPos.y() == event->y())return;QPoint MovePos = QCursor::pos();QPoint currentPos = mapFromGlobal(MovePos);int xoffset = 0;int yoffset = 0;xoffset  =  currentPos.x() - m_cursorPos.x();yoffset  =  currentPos.y() - m_cursorPos.y();if( xoffset>0  && (yoffset>=-15 && yoffset<=15)){nDerection = 0;}else if(xoffset<0 && (yoffset>=-15 && yoffset<=15)){nDerection = 1;}else if(yoffset>0 && (xoffset>=-15 && xoffset<=15))//down{nDerection = 2;}else if(yoffset<0 && (xoffset>=-15 && xoffset<=15))//up{nDerection = 3;}qDebug()<<"1111111111"<<m_xRos<<nDerection<<xoffset<<yoffset;timer->start();
}void testshadeWidget::mousePressEvent(QMouseEvent *event)
{if(event->button() == Qt::LeftButton){m_cursorGlobalPos = QCursor::pos();m_cursorPos = mapFromGlobal(m_cursorGlobalPos);}
}void testshadeWidget::paintGL()
{glClearColor(0.1f, 0.1f, 0.1f, 1.0f);  //设置清屏颜色glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//    //开启深度测试//glEnable(GL_DEPTH_TEST);
//    //开启遮挡剔除// glEnable(GL_CULL_FACE);QMatrix4x4 m;m.translate(m_xRos, m_yRos, m_zRos);m.rotate(xRot / 16.0f, 1.0f, 0.0f, 0.0f);m.rotate(yRot / 16.0f, 0.0f, 1.0f, 0.0f);m.rotate(zRot / 16.0f, 0.0f, 0.0f, 1.0f);m.scale(0.5);program->bind();QMatrix4x4 view;view.lookAt(QVector3D(0,0,3), QVector3D(0,0,3)+QVector3D(0,0,-1), QVector3D(0,1,0));QMatrix4x4 projection;projection.perspective(45.0f,float(this->width())/float(this->height()),0.1f,100.0f);program->setUniformValue("model", m);program->setUniformValue("view", view);program->setUniformValue("projection", projection);program->setUniformValue("objectColor", QVector3D(1.0f, 0.5f, 0.3f));//物体颜色program->setUniformValue("lightColor", QVector3D( 1.0f, 1.0f, 1.0f));program->setUniformValue("lightPos", QVector3D(1.2f, 1.0f, 2.0f));//光位置for(int i=0;i<6;i++){glDrawArrays(GL_TRIANGLE_FAN, i*4, 4);}vao.bind(); lightprogram->bind();QMatrix4x4 model;model.translate(0.5f, 0.5f, 0.5f);model.scale(0.2);lightprogram->setUniformValue("view", view);lightprogram->setUniformValue("model", model);lightprogram->setUniformValue("projection", projection);lightVao.bind();//glDrawArrays(GL_TRIANGLES, 0, 36);for(int i=0;i<6;i++){glDrawArrays(GL_TRIANGLE_FAN, i*4, 4);}}void testshadeWidget::resizeGL(int width, int height)
{
//    QMatrix4x4 projection;
//    projection.perspective(m_verticalAngle, width/height, 0.01, 100);
//    // m_verticalAngle: 设置垂直角度(值越大,那么物体越小)
//    // width()/height(): 设置宽高比
//    // 0.1 100: 设置近远平面距离
//    glUseProgram(program->programId());
//    program->setUniformValue("projection", projection);this->glViewport(0,0,width,height);                //定义视口区域this->update();
}
#ifndef TESTSHADEWIDGET_H
#define TESTSHADEWIDGET_H#include <QWidget>
#include <QOpenGLWidget>
#include <QOpenGLExtraFunctions>
#include <QOpenGLBuffer>
#include <QOpenGLShaderProgram>
#include <QOpenGLVertexArrayObject>
#include <QTimer>
#include <QOpenGLTexture>
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QOpenGLBuffer>
#include <QOpenGLVertexArrayObject>
#include <QTimer>
#include <QMouseEvent>QT_FORWARD_DECLARE_CLASS(QOpenGLShaderProgram);
QT_FORWARD_DECLARE_CLASS(QOpenGLTexture)
class testshadeWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
public:testshadeWidget();~testshadeWidget();
protected:void initializeGL() override;void paintGL() override;void resizeGL(int width, int height) override;void rotateBy(int xAngle, int yAngle, int zAngle);void mouseMoveEvent(QMouseEvent *event) override;void mouseReleaseEvent(QMouseEvent *event) override;void mousePressEvent(QMouseEvent *event) override;void offsetBy(int xPos, int yPos, int zPos);
private:QOpenGLTexture *textures[6] = {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr};QOpenGLShaderProgram *program = nullptr;QOpenGLBuffer vbo;QVector<float> vertices;QOpenGLVertexArrayObject vao;QTimer* timer;float m_xRos = 0.0f;float m_yRos = 0.0f;float m_zRos = 0.0f;QVector3D cameraPos;QVector3D cameraTarget;QVector3D cameraDirection;QOpenGLTexture *texture;QMatrix4x4 projection;QVector3D   cam;int xRot = 0;int yRot = 0;int zRot = 0;QPoint m_cursorPos;QPoint m_cursorGlobalPos;int nDerection=0;QVector3D lightPos;float m_verticalAngle;      // 视角缩放QOpenGLShaderProgram *lightprogram = nullptr;QOpenGLVertexArrayObject lightVao;QOpenGLBuffer *_ebo;};#endif // TESTSHADEWIDGET_H

我们运行下

这里是不是有阴影和光照了。

我们来解释下方向量的定义。

我们看下正面这个面,垂直于这个面的是不是Z轴,那就是z轴是1,其他是0,在看垂直于这个面的是不是Z轴反方向,所以是-1,所以法向量是0,0,-1。

相关文章:

qt + opengl 给立方体增加阴影

在前几篇文章里面学会了通过opengl实现一个立方体&#xff0c;那么这篇我们来学习光照。 风氏光照模型的主要结构由3个分量组成&#xff1a;环境(Ambient)、漫反射(Diffuse)和镜面(Specular)光照。下面这张图展示了这些光照分量看起来的样子&#xff1a; 1 环境光照(Ambient …...

buuctf-[极客大挑战 2019]Knife题解

一个很简单的web题&#xff0c;进入界面 网页名还加白给的shell&#xff0c;并且给的提示也很明显&#xff0c;给了一个一句话木马再加上菜刀&#xff0c;很怀疑是一个webshell题&#xff0c;那么直接打开蚁剑测试连接拿shell 用提示的一句话木马的密码&#xff0c;测试链接发现…...

常用电脑,护眼软件推荐 f.lux 3400K | 撰写论文 paper

常用电脑&#xff1f;平均每天用 5 个小时&#xff1f;你就要考虑用一个护眼软件了&#xff0c;对皮肤也好。因为电脑屏幕有辐射&#xff0c;比如蓝光。 f.lux 作为一款专业护眼软件&#xff0c;值得使用。之前用了三年的 Iris Pro&#xff0c;现在 f.lux 做的更好了。 使用…...

【操作幂等和数据一致性】保障业务在MySQL和COS对象存储的一致

业务场景 发布信息&#xff0c;更新到数据库MySQLCOS操作&#xff0c;更新JSON文件 不过可能存在幂等性和数据一致性的问题。 // 批量存MySQL entityPublishService.saveOrUpdateBatch(entityPublishList); // 遍历批量存COS对象存储searchEntitys.forEach(req -> {//删除…...

[答疑]领域建模:邓丽君、周杰伦和少女时代

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 第五元素 2025-2-18 17:12 潘老师&#xff0c;画线的这句话&#xff0c;在这个类图中怎么体现呢&#xff1f; &#xff08;回答者补注&#xff1a;问题的素材来自《邓丽君的领域建模》…...

【鸿蒙开发】第四十三章 Notification Kit(用户通知服务)

目录​​​​​​​ 1 简介 1.1 使用场景 1.2 能力范围 1.3 业务流程 1.4 通知样式 1.5 约束限制 1.6 与相关Kit的关系 2 请求通知授权 2.1 接口说明 2.2 开发步骤 3 管理通知角标 3.1 接口说明 3.2 开发步骤 4 管理通知渠道 4.1 通知渠道类型说明 4.2 接口说明…...

Ubuntu 20.04源码安装opencv 4.5.0

安装依赖项 sudo apt install -y g sudo apt install -y cmake sudo apt install -y make sudo apt install -y wget unzip安装opencv依赖库 sudo apt-get install build-essential libgtk2.0-dev libgtk-3-dev libavcodec-dev libavformat-dev libjpeg-dev libswscale-dev l…...

buu-get_started_3dsctf_2016-好久不见39

栈溢出外平栈 1外平栈与内平栈的区别 外平栈&#xff1a; 栈帧的局部变量和返回地址之间没有额外的对齐或填充。返回地址直接位于局部变量的上方&#xff08;即栈顶方向&#xff09;。在计算偏移时&#xff0c;不需要额外加 4&#xff08;因为返回地址紧邻局部变量&#xff09…...

一周学会Flask3 Python Web开发-客户端状态信息Cookie以及加密

锋哥原创的Flask3 Python Web开发 Flask3视频教程&#xff1a; 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili HTTP是无状态&#xff08;stateless)协议。也就是说&#xff0c;在一次请求响应结束后&#xff0c;服务器不会留下任何关于对…...

深入解析Qt事件循环

在Qt开发中&#xff0c;QApplication::exec()这行代码是每个开发者都熟悉的“魔法咒语”。为什么GUI程序必须调用它才能响应操作&#xff1f;为何耗时操作会导致界面冻结&#xff1f;本文将以事件循环为核心&#xff0c;揭示Qt高效运转的底层逻辑&#xff0c;探讨其设计哲学与最…...

python中的异常-模块-包

文章目录 异常异常的定义异常捕获语法捕获常规异常捕获指定异常捕获多个异常捕获所有异常异常else异常finally 异常传递总结 模块概念导入自定义模块及导入main方法all变量 总结 包自定义包定义pycharm中建包的基本步骤导入方式 第三方包 异常 异常的定义 当检测到一个错误时…...

AI 百炼成神:线性回归,预测房价

我们开始第一个项目——线性回归:预测房价。这是一个经典的机器学习入门项目,可以帮助你理解如何使用线性回归模型来预测连续的数值。 第一个项目:线性回归预测房价 项目目标 学习线性回归的基本概念。使用历史房价数据建立一个预测模型。理解如何评估模型的性能。项目步骤…...

Grok-3 与 DeepSeek 的技术架构与性能分析

随着 AI 大模型技术的快速发展,Grok-3(xAI)与 DeepSeek-V3/R1(深度求索)成为近期备受关注的焦点。本文将从技术架构、性能表现、成本效率和应用场景等维度,深入对比分析这两大模型的优劣势。 一、技术架构对比 1. DeepSeek-V3/R1:高效 MoE 架构与工程优化 混合专家模型…...

机器学习实战(4):逻辑回归——分类问题的基础

第4集&#xff1a;逻辑回归——分类问题的基础 在机器学习中&#xff0c;逻辑回归&#xff08;Logistic Regression&#xff09; 是解决分类问题的经典算法之一。尽管名字中有“回归”&#xff0c;但它实际上是一种分类模型&#xff0c;广泛应用于二分类任务&#xff08;如垃圾…...

我是如何从 0 到 1 找到 Web3 工作的?

作者&#xff1a;Lotus的人生实验 关于我花了一个月的时间&#xff0c;从 0 到 1 学习 Web3 相关的知识和编程知识。然后找到了一个 Web3 创业公司实习的远程工作。 &#x1f447;&#x1f447;&#x1f447; 我的背景: 计算机科班&#xff0c;学历还可以(大厂门槛水平) 毕业工…...

基于WebRTC与AI大模型接入EasyRTC:打造轻量级、高实时、强互动的嵌入式音视频解决方案

随着物联网和嵌入式技术的快速发展&#xff0c;嵌入式设备对实时音视频通信的需求日益增长。然而&#xff0c;传统的音视频解决方案往往存在体积庞大、实时性差、互动体验不佳等问题&#xff0c;难以满足嵌入式设备的资源限制和应用场景需求。 针对以上痛点&#xff0c;本文将介…...

【DeepSeek】本地部署,保姆级教程

deepseek网站链接传送门&#xff1a;DeepSeek 在这里主要介绍DeepSeek的两种部署方法&#xff0c;一种是调用API&#xff0c;一种是本地部署。 一、API调用 1.进入网址Cherry Studio - 全能的AI助手选择立即下载 2.安装时位置建议放在其他盘&#xff0c;不要放c盘 3.进入软件后…...

Java 大视界 -- 国际竞争与合作:Java 大数据在全球市场的机遇与挑战(94)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…...

流程绩效分析,实现销售目标的保障

在当今竞争激烈的商业环境里&#xff0c;客户关系管理&#xff08;CRM&#xff09;行业正迎来深刻变革。企业若想在市场中脱颖而出&#xff0c;实现业务的持续增长&#xff0c;流程绩效分析成为关键。通过提供销售全流程绩效分析能力&#xff0c;企业能够针对销售全流程的复杂业…...

Linux NFS

Linux NFS NFS&#xff08;Network File System&#xff09;是一种用于在网络上共享文件系统的协议&#xff0c;允许不同的计算机通过网络访问和共享文件&#xff0c;就像访问本地文件一样。它广泛应用于 Linux 和 UNIX 系统中&#xff0c;支持多用户并发访问&#xff0c;适合…...

一文精通JWT Token、ID Token、Access Token、Refresh Token

JWT Token JSON Web Token (JWT,RFC 7519 (opens new window)),是为了在网络应用环境间传递声明而执行的一种基于 JSON 的开放标准((RFC 7519)。该 token 被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT 的声明一般被用来在身份提供者和服务提供者…...

CSS基础(浮动、相对定位、绝对定位、固定定位、粘性定位、版心、重置默认样式)

文章目录 1. 浮动&#xff08;float&#xff09;1.1 简介1.2 元素浮动后的特点1.3 脱离文档流示例图1.4 浮动产生的影响1.4.1 积极影响1.4.2 消极影响 1.5 解决浮动产生的影响1.5.1 清除浮动&#xff08;Clearfix&#xff09;1.5.2 创建新的块格式化上下文&#xff08;BFC&…...

uniapp中引入Vant Weapp的保姆级教学(包含错误处理)

废话不多说&#xff0c;直接上方法&#xff0c;网上的教学好多都是错误的 1.安装vant weapp 在Hbuilder的终端&#xff0c;输入以下代码 npm install vant/weapp -S --production 2.新建wxcomponents文件夹 在项目的跟目录新建一个“wxcomponents’文件夹&#xff0c;与app.…...

Datawhale Ollama教程笔记5

Dify 接入 Ollama 部署的本地模型 Dify 支持接入 Ollama 部署的大型语言模型推理和 embedding 能力。 快速接入 下载 Ollama 访问 Ollama 安装与配置&#xff0c;查看 Ollama 本地部署教程。 运行 Ollama 并与 Llama 聊天 ollama run llama3.1Copy to clipboardErrorCopied …...

STL —— 洛谷字符串(string库)入门题(蓝桥杯题目训练)(二)

目录 一、B2121 最长最短单词 - 洛谷 算法代码&#xff1a; 代码分析 变量定义 输入处理 单词长度计算 更新最长和最短单词的长度 输出最长单词 输出最短单词 评测记录&#xff1a;​编辑 二、B2122 单词翻转 - 洛谷 算法代码&#xff1a; 代码分析 引入头文件和定…...

P1055 [NOIP 2008 普及组] ISBN 号码(java)【AC代码】

每一本正式出版的图书都有一个 ISBN 号码与之对应&#xff0c;ISBN 码包括 9 位数字、1 位识别码和 3 位分隔符&#xff0c;其规定格式如 x-xxx-xxxxx-x&#xff0c;其中符号 - 就是分隔符&#xff08;键盘上的减号&#xff09;&#xff0c;最后一位是识别码&#xff0c;例如 0…...

JavaScript如何创建一个对象?对象字面量和构造函数创建对象有什么区别?

JavaScript如何创建一个对象&#xff1f;对象字面量和构造函数创建对象有什么区别&#xff1f; JavaScript 创建对象的方式 在 JavaScript 中&#xff0c;有多种方式可以创建对象&#xff0c;这里主要介绍对象字面量和构造函数这两种常见的方式。 1. 对象字面量 对象字面量…...

【量化科普】Sharpe Ratio,夏普比率

【量化科普】Sharpe Ratio&#xff0c;夏普比率 &#x1f680;&#x1f680;&#x1f680;量化软件开通&#x1f680;&#x1f680;&#x1f680; &#x1f680;&#x1f680;&#x1f680;量化实战教程&#x1f680;&#x1f680;&#x1f680; 在量化投资领域&#xff0c;…...

知识蒸馏知识点

1基于kl散度计算,学生模型需要用log_softmax处理 2 为了避免温度对梯度的影响,loss*T**2 操作目的教师 / 学生输出除以 软化概率分布,暴露类别间关系损失乘以 抵消温度对梯度的缩放,维持梯度量级稳定,确保训练收敛性 import torch import torch.nn.functional as F# 原…...

Springboot + Ollama + IDEA + DeepSeek 搭建本地deepseek简单调用示例

1. 版本说明 springboot 版本 3.3.8 Java 版本 17 spring-ai 版本 1.0.0-M5 deepseek 模型 deepseek-r1:7b 需要注意一下Ollama的使用版本&#xff1a; 2. springboot项目搭建 可以集成在自己的项目里&#xff0c;也可以到 spring.io 生成一个项目 生成的话&#xff0c;如下…...

【MySQL】MySQL表的增删改查(进阶)

1.❤️❤️前言~&#x1f973;&#x1f389;&#x1f389;&#x1f389; Hello, Hello~ 亲爱的朋友们&#x1f44b;&#x1f44b;&#xff0c;这里是E绵绵呀✍️✍️。 如果你喜欢这篇文章&#xff0c;请别吝啬你的点赞❤️❤️和收藏&#x1f4d6;&#x1f4d6;。如果你对我的…...

装修流程图: 装修前准备 → 设计阶段 → 施工阶段 → 安装阶段 → 收尾阶段 → 入住

文章目录 引言I 毛坯房装修的全流程**1. 装修前准备****1.1 确定装修预算****1.2 选择装修方式****1.3 选择装修公司****1.4 办理装修手续****2. 设计阶段****2.1 量房****2.2 设计方案****2.3 确认方案****3. 施工阶段****3.1 主体拆改****3.2 水电改造****3.3 防水工程****3.…...

JavaScript系列(79)--Web Worker 高级应用

Web Worker 高级应用 &#x1f504; Web Worker 为JavaScript提供了真正的多线程能力&#xff0c;让我们能够在后台线程中执行复杂的计算而不阻塞主线程。今天让我们深入探讨Web Worker的高级应用。 Web Worker 概述 &#x1f31f; &#x1f4a1; 小知识&#xff1a;Web Work…...

人工智能之自动驾驶技术体系

自动驾驶技术体系 自动驾驶技术是人工智能在交通领域的重要应用&#xff0c;旨在通过计算机视觉、传感器融合、路径规划等技术实现车辆的自主驾驶。自动驾驶不仅能够提高交通效率&#xff0c;还能减少交通事故和环境污染。本文将深入探讨自动驾驶的技术体系&#xff0c;包括感…...

该如何搭建高效的跨境网络专线?

在如今这个全球化的商业环境中&#xff0c;跨境网络专线成为了企业与个人实现高效、安全跨国通信的重要工具。大家好&#xff0c;在接下来的内容中&#xff0c;我将深入为您探讨跨境网络专线的概念、特点以及搭建流程&#xff0c;帮助您更好地理解和利用这一技术。 一、什么是…...

网络运维学习笔记 017HCIA-Datacom综合实验01

文章目录 综合实验1实验需求总部特性 分支8分支9 配置一、 基本配置&#xff08;IP二层VLAN链路聚合&#xff09;ACC_SWSW-S1SW-S2SW-Ser1SW-CoreSW8SW9DHCPISPGW 二、 单臂路由GW 三、 vlanifSW8SW9 四、 OSPFSW8SW9GW 五、 DHCPDHCPGW 六、 NAT缺省路由GW 七、 HTTPGW 综合实…...

Redis数据结构-String字符串

1.String字符串 字符串类型是Redis中最基础的数据结构&#xff0c;关于数据结构与要特别注意的是&#xff1a;首先Redis中所有的键的类型都是字符串类型&#xff0c;而且其他集中数据结构也都是在字符串类似基础上进行构建&#xff0c;例如列表和集合的元素类型是字符串类型&a…...

个人简历html网页模板,科技感炫酷html简历模板

炫酷动效登录页 引言 在网页设计中,按钮是用户交互的重要元素之一。这样一款黑色个人简历html网页模板,科技感炫酷html简历模板,设计效果类似科技看板图,可帮您展示技能、任职经历、作品等,喜欢这种风格的小伙伴不要犹豫哦。该素材呈现了数据符号排版显示出人形的动画效…...

【Python爬虫(39)】掌控全局:分布式爬虫的任务管理与监控之道

【Python爬虫】专栏简介&#xff1a;本专栏是 Python 爬虫领域的集大成之作&#xff0c;共 100 章节。从 Python 基础语法、爬虫入门知识讲起&#xff0c;深入探讨反爬虫、多线程、分布式等进阶技术。以大量实例为支撑&#xff0c;覆盖网页、图片、音频等各类数据爬取&#xff…...

输入框元素覆盖冲突

后端响应中的 "trainingKbGroupName": "基础死型" 通过searchForm2.initFormData(rowData[0]);操作会把基础死型四个字填充到<div class"col-sm-5 form-group"> <label class"col-sm-3 control-label">知识点分组名称<…...

R语言学习笔记——确定指标权重:层次分析法/熵权法/CRITIC方法

本文介绍使用R语言确定指标权重的方法&#xff0c;包括&#xff1a;层次分析法、熵权法和CRITIC方法&#xff0c;内容包含了逆向指标正向化处理。 1、层次分析法 #######层次分析法###### ###几何平均法求权重 options(digits 2) library(tidyverse)macro <- tibble(x1c(…...

前端面试之Box盒子布局:核心知识与实战解析

目录 引言&#xff1a;布局能力决定前端高度 一、盒模型基础&#xff1a;看得见的像素战争 1. 标准盒模型 vs IE盒模型 2. 核心组成公式 3. 视觉格式化模型 二、传统布局三剑客 1. 浮动布局&#xff08;Float Layout&#xff09; 2. 定位布局&#xff08;Position Layou…...

前端VUE+后端uwsgi 环境搭建

1整体架构 请求流程the web clinet--the web server->the socket->uwsgi--django 第一级的nginx并不是必须的&#xff0c;uwsgi完全可以完成整个的和浏览器交互的流程&#xff1b;在nginx上加上安全性或其他的限制&#xff0c;可以达到保护程序的作用&#xff1b;uWSGI本…...

保姆级! 本地部署DeepSeek-R1大模型 安装Ollama Api 后,Postman本地调用 deepseek

要在Postman中访问Ollama API并调用DeepSeek模型&#xff0c;你需要遵循以下步骤。首先&#xff0c;确保你有一个有效的Ollama服务器实例运行中&#xff0c;并且DeepSeek模型已经被加载。 可以参考我的这篇博客 保姆级&#xff01;使用Ollama本地部署DeepSeek-R1大模型 并java…...

【python】pip命令合集

文章目录 1. 包安装与卸载2. 依赖管理与文件操作3. 包下载与构建4. 配置与缓存管理5. 高级调试与日志6. 虚拟环境集成7. 哈希验证与安全8. 实验性功能&#xff08;可能不稳定&#xff09;9. 其他实用命令参数大全&#xff08;全局常用参数&#xff09;示例场景 conda: 【python…...

【鸿蒙开发】第四十章 Form Kit(卡片开发服务)

目录 1 概述 1.1 卡片使用场景 1.2 服务卡片架构 1.3 亮点/特征 1.4 开发模式 1.5 与相关Kit的关系 1.6 约束限制 2 ArkTS卡片运行机制 2.1 实现原理 2.2 ArkTS卡片的优势 2.3 ArkTS卡片的约束 3 ArkTS卡片相关模块 4 ArkTS卡片开发指导 4.1 创建一个ArkTS卡片 …...

汽车自动驾驶辅助L2++是什么?

自动驾驶辅助级别有哪些&#xff1f; 依照SAE&#xff08;SAE International&#xff0c;Society of Automotive Engineers国际自动机工程师学会&#xff09;的标准&#xff0c;大致划分为6级&#xff08;L0-L5&#xff09;&#xff1a; L0人工驾驶&#xff1a;即没有驾驶辅助…...

微信小程序消息推送解密

package com.test.main.b2b;import org.apache.commons.codec.binary.Base64;import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.util.Arrays;/*** author * version 1.0* description: 解谜微信小…...

java项目之城市公园信息管理系统的设计与实现(源码+文档)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于ssm的城市公园信息管理系统的设计与实现。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 城市公园信息…...

EasyRTC:基于WebRTC与P2P技术,开启智能硬件音视频交互的全新时代

在数字化浪潮的席卷下&#xff0c;智能硬件已成为我们日常生活的重要组成部分&#xff0c;从智能家居到智能穿戴&#xff0c;从工业物联网到远程协作&#xff0c;设备间的互联互通已成为不可或缺的趋势。然而&#xff0c;高效、低延迟且稳定的音视频交互一直是智能硬件领域亟待…...