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

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 = 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 …...

vue2老版本 npm install 安装失败_安装卡主

vue2老版本 npm install 安装失败_安装卡主 特别说明&#xff1a;vue2老版本安装慢、运行慢&#xff0c;建议升级vue3element plus vite 解决方案1&#xff1a; 第一步、修改npm 镜像为国内镜像 使用淘宝镜像&#xff1a; npm config set registry https://registry.npmmir…...

20250213编译飞凌的OK3588-C_Linux5.10.209+Qt5.15.10_用户资料_R1

20250213编译飞凌的OK3588-C_Linux5.10.209Qt5.15.10_用户资料_R1 2025/2/13 11:43 缘起&#xff1a;飞凌发布了高版本内核的适配OK3588-C的Buildroot的SDK&#xff1a;OK3588-C_Linux5.10.209Qt5.15.10_用户资料_R1。 但是编译异常了。 于是按照百度升级libc6&#xff0c;可以…...

中望CAD c#二次开发 ——VS环境配置

新建类库项目&#xff1a;下一步 下一步 下一步&#xff1a; 或直接&#xff1a; 改为&#xff1a; <Project Sdk"Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>NET48</TargetFramework> <LangVersion>pr…...

【Elasticsearch】词干提取(Stemming)

词干提取是将一个词还原为其词根形式的过程。这确保了在搜索过程中&#xff0c;一个词的不同变体能够匹配到彼此。 例如&#xff0c;walking&#xff08;行走&#xff09;和walked&#xff08;走过&#xff09;可以被还原到同一个词根walk&#xff08;走&#xff09;。一旦被还…...

Rander压力测试监测,更改服务端资源node

测试策略 压力测试&#xff0c; 目前是本地VM的资源不够&#xff0c;导致压力瓶颈&#xff0c;目前本地的VM&#xff0c;CPU是6个&#xff0c;可以增加到8个&#xff0c;服务端目前资源利用率没有达到最高点 we are now using 3 nodes with 3 pods, therefore, we need the …...

Go语言实现十大排序算法超细节图片讲解

基础排序 冒泡排序 将序列中的元素进行两两比较&#xff0c;将大的元素移动到序列的末尾。 平均时间复杂度是O(n^2)&#xff0c;最坏时间复杂度是O(n^2)&#xff0c;最好时间复杂度是O(n)&#xff0c;排序结果具有稳定性&#xff0c;空间复杂度是O(1)。 这里所说的稳定性是针对…...

linux-centos等测试环境做压力测试

一, jmeter环境安装 1, jdk下载安装 因为jmeter使用Java写的测试工具,应用需要jdk环境支持. yum -y install java-1.8.0-openjdk* 注意&#xff1a;【jdk和*通配符之间不能敲空格&#xff0c;有空格不能匹配所有的子文件】【安装过程中需要等待它执行完成&#xff0c;不要中…...

Django中实现可靠的定时任务调度系统

在许多Web应用程序中,定时任务是一个常见的需求。无论是数据同步、报告生成还是定期维护,都需要一个可靠的调度系统。本文将介绍如何在Django项目中实现一个强大的定时任务调度系统,该系统不仅能够按时执行任务,还能处理分布式环境中的并发问题。 1. 概述 我们将使用以下…...

【鸿蒙Next】写入沙箱的日志文件如何查看

demo案例&#xff1a;https://gitee.com/pengyoucongcode/TxtEdit 文章参考&#xff1a;https://blog.csdn.net/qq_42896653/article/details/144782468...

网页五子棋——通用模块

目录 项目创建 通用功能模块 错误码 自定义异常类 CommonResult jackson 加密工具 项目创建 使用 idea 创建 SpringBoot 项目&#xff0c;并引入相关依赖&#xff1a; 配置 MyBatis&#xff1a; 编辑 application.yml&#xff1a; spring:datasource: # 数据库连接配…...

第6章 6.2使用ASP.NET Core 开发WebAPI ASP.NET Core Web API

6.2.1 Web API项目的搭建 进入VS&#xff0c;【创建新项目】&#xff0c;选择【ASP.NET Core Web API】模板&#xff0c;【下一步】&#xff0c;编辑项目名称及项目位置&#xff0c;【下一步】&#xff0c;选择框架&#xff0c;其他选项默认即可&#xff0c;【创建】。 进入项…...

[MFC] 使用控件

介绍如何使用控件&#xff0c;以及如何获取控件中的数值 check Box 添加点击事件&#xff0c;即选中和取消选中触发的事件 第一种方式是按照如下方式第二种方式是直接双击点击进去 void CMFCApplication1Dlg::OnBnClickedCheckSun() {// TODO: 在此添加控件通知处理程序代…...

景联文科技:以精准标注赋能AI未来,打造高质量数据基石

在人工智能蓬勃发展的时代&#xff0c;数据已成为驱动技术革新的核心燃料&#xff0c;而高质量的数据标注则是让AI模型从“感知”走向“认知”的关键桥梁。作为深耕数据服务领域的创新者&#xff0c;景联文科技始终以“精准、高效、安全”为核心理念&#xff0c;为全球AI企业提…...

2月14(信息差)

&#x1f30d;杭州&#xff1a;全球数贸港核心区建设方案拟出台 争取国家支持杭州在网络游戏管理给予更多权限 &#x1f384;Kimi深夜炸场&#xff1a;满血版多模态o1级推理模型&#xff01;OpenAI外全球首次&#xff01;Jim Fan&#xff1a;同天两款国产o1绝对不是巧合&#x…...

UE_C++ —— Metadata Specifiers

声明UClasses、UFunctions、UProperties、UEnums和UInterfaces时使用的元数据关键词&#xff0c;表示其与引擎和关卡编辑器诸多方面的互动方式&#xff1b; 当声明classe、interfaces、structs、enums、enum values、functions、or propertie时&#xff0c;可添加 Metadata Spe…...

C++ 常用的设计模式

1&#xff1a;单例模式&#xff1a;首先能想到的&#xff0c;最为重要的一个设计模式。确保一个类仅有一个实例&#xff0c;提供一个 全局访问点&#xff0c;惯用做法是屏蔽构造数访问&#xff08;设为private&#xff09;&#xff0c;通过static 权限达到间接访问调用的目的…...

web集群(LVS-DR)

LVS是Linux Virtual Server的简称&#xff0c;也就是Linux虚拟服务器, 是一个由章文嵩博士发起的自由软件项 目&#xff0c;它的官方站点是 www.linuxvirtualserver.org。现在LVS已经是 Linux标准内核的一部分&#xff0c;在 Linux2.4内核以前&#xff0c;使用LVS时必须要重新编…...

Instagram与小红书的自动化运营

Instagram与小红书的自动化运营 引言 在这个信息爆炸的时代&#xff0c;社交媒体成为了与世界互动的重要平台。在这样的背景下&#xff0c;如何高效地运营你的Instagram或小红书账户&#xff0c;成为众多内容创作者和品牌的重要课题。那么&#xff0c;自动化运营究竟是什么&a…...

从二维到三维3D工业相机如何改变机器视觉检测

从二维到三维&#xff0c;3D工业相机在机器视觉检测中带来了显著变革&#xff0c;主要体现在以下几个方面&#xff1a; 深度信息获取 二维相机&#xff1a;只能提供平面信息&#xff0c;无法获取物体的深度。 三维相机&#xff1a;通过深度信息&#xff0c;能够更精确地测量物…...

多媒体软件安全与授权新范例,用 CodeMeter 实现安全、高效的软件许可管理

背景概述 Reason Studios 成立于 1994 年&#xff0c;总部位于瑞典斯德哥尔摩&#xff0c;是全球领先的音乐制作软件开发商。凭借创新的软件产品和行业标准技术&#xff0c;如 ReWire 和 REX 文件格式&#xff0c;Reason Studios 为全球专业音乐人和业余爱好者提供了一系列高质…...

DeePseek结合PS!批量处理图片的方法教程

​ ​ 今天我们来聊聊如何利用deepseek和Photoshop&#xff08;PS&#xff09;实现图片的批量处理。 传统上&#xff0c;批量修改图片尺寸、分辨率等任务往往需要编写脚本或手动处理&#xff0c;而现在有了AI的辅助&#xff0c;我们可以轻松生成PS脚本&#xff0c;实现自动化处…...

2.14寒假作业

web&#xff1a;[SWPUCTF 2021 新生赛]PseudoProtocols 打开环境给了提示要我们找 hint.php url是给了后缀的&#xff0c;不单纯是地址&#xff0c;直接用为协议看一下目标文件&#xff0c;得到base64加密的文字 解密&#xff0c;提示我们访问一个文件 跟着思路走访问文件之后…...

【鱼眼镜头12】Scaramuzza的鱼眼相机模型实操,不依赖于具体的相机几何结构,直接从图像数据出发,因此更具灵活性。

文章目录 Scaramuzza相机模型标定效果2、原理和代码代码1、 2D映射到3D&#xff0c;函数输入为2D点坐标OCAM参数代码功能详解2、3D --> 2D 3、总结Scaramuzza 模型的核心思想Scaramuzza 模型的核心思想与 Kannala-Brandt 模型的对比Scaramuzza 模型的独特之处Scaramuzza 的意…...

(Windows | Linux)ssh访问服务器报错:no matching key exchange method found

问题现象 ssh user1192.168.1X.XX Unable to negotiate with 192.168.1X.XX port 22: no matching key exchange method found. Their offer: gss-group1-sha1-toWM5Slw5Ew8Mqkayal2g,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1,diffie-hellman-group1-…...

达梦分布式集群DPC_架构详解_yxy

达梦分布式集群DPC_架构详解 1 DPC核心架构介绍1.1 架构图1.2 DPC核心架构组件 2 多副本2.1 多副本架构图2.2 多副本示例2.3 RAFT组概念2.4 表空间与RAFT组的关系 1 DPC核心架构介绍 1.1 架构图 1.2 DPC核心架构组件 DMDPC 架构由三部分组成 SP&#xff08;SQL Processor&…...

51单片机独立按键的扩展应用

提示&#xff1a; 按键S7和S6为选择键&#xff0c;确定控制键控制那组LED指示灯。按键S5和S4为控制键&#xff0c;按键该键点亮指定的LED指示灯&#xff0c;松开后熄灭。按下S7点亮L1指示灯&#xff0c;L1点亮后&#xff0c;S6不响应操作&#xff0c;S5控制L3&#xff0c;S4控…...

浅识MQ的 Kafka、ActiveMQ、RabbitMQ、RocketMQ区别

DeepSeek回复&#xff1a; 以下是主流消息队列&#xff08;MQ&#xff09;的对比分析&#xff0c;结合核心特性、适用场景和实际案例说明&#xff1a; 一、主流MQ对比分析 维度 Kafka RabbitMQ RocketMQ ActiveMQ所属公司Apache&#xff08;LinkedIn开源&#xff09;…...

模型报错infeasible,如何查看冲突约束

在使用Gurobi求解模型时&#xff0c;如果模型不可行&#xff08;infeasible&#xff09;&#xff0c;可以通过以下步骤来查看冲突的约束或变量&#xff0c;帮助诊断问题&#xff1a; 1. 使用 computeIIS() 方法 Gurobi 提供了 computeIIS() 方法&#xff0c;用于计算不可行模…...

Golang GORM系列:GORM事务及错误处理

在数据库管理领域&#xff0c;确保数据完整性至关重要。GORM是健壮的Go对象关系映射库&#xff0c;它为开发人员提供了维护数据一致性和优雅地处理错误的基本工具。本文是掌握GORM事务和错误处理的全面指南。我们将深入研究如何使用事务来保证原子性&#xff0c;并探索有效处理…...