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。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/70207.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/70207.shtml
英文地址,請注明出處:http://en.pswp.cn/web/70207.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

大模型工具大比拼:SGLang、Ollama、VLLM、LLaMA.cpp 如何選擇?

簡介&#xff1a;在人工智能飛速發展的今天&#xff0c;大模型已經成為推動技術革新的核心力量。無論是智能客服、內容創作&#xff0c;還是科研輔助、代碼生成&#xff0c;大模型的身影無處不在。然而&#xff0c;面對市場上琳瑯滿目的工具&#xff0c;如何挑選最適合自己的那…

stream流常用方法

1.reduce 在Java中&#xff0c;可以使用Stream API的reduce方法來計算一個整數列表的乘積。reduce方法是一種累積操作&#xff0c;它可以將流中的元素組合起來&#xff0c;返回單個結果。對于計算乘積&#xff0c;你需要提供一個初始值&#xff08;通常是1&#xff0c;因為乘法…

pgAdmin4在mac m1上面簡單使用(Docker)

問題 想要在本地簡單了解一下pgAdmin4一些簡單功能。故需要在本機先安裝看一看。 安裝步驟 拉取docker鏡像 docker pull dpage/pgadmin4直接簡單運行pgAdmin4 docker run --name pgAdmin4 -p 5050:80 \-e "PGADMIN_DEFAULT_EMAILuserdomain.com" \-e "PGAD…

ubuntu下安裝TFTP服務器

在 Ubuntu 系統下安裝和配置 TFTP&#xff08;Trivial File Transfer Protocol&#xff09;服務器可以按照以下步驟進行&#xff1a; 1. 安裝 TFTP 服務器軟件包 TFTP 服務器通常使用 tftpd-hpa 軟件包&#xff0c;你可以使用以下命令進行安裝&#xff1a; sudo apt update …

Softing線上研討會 | 自研還是購買——用于自動化產品的工業以太網

| 線上研討會時間&#xff1a;2025年1月27日 16:00~16:30 / 23:00~23:30 基于以太網的通信在工業自動化網絡中的重要性日益增加。設備制造商正面臨著一大挑戰——如何快速、有效且經濟地將工業以太網協議集成到其產品中。其中的關鍵問題包括&#xff1a;是否只需集成單一的工…

vscode創建java web項目

一.項目部署 1.shiftctrlp&#xff0c;選擇java項目 2.選擇maven create from arcetype 3.選擇webapp 4.目錄結構如下&#xff0c;其中index.jsp是首頁 5.找到左下角的servers,添加tomcat服務器 選擇 再選擇&#xff1a; 找到你下載的tomcat 的bin目錄的上一級目錄&#x…

C語言指針學習筆記

1. 指針的定義 指針&#xff08;Pointer&#xff09;是存儲變量地址的變量。在C語言中&#xff0c;指針是一種非常重要的數據類型&#xff0c;通過指針可以直接訪問和操作內存。 2. 指針的聲明與初始化 2.1 指針聲明 指針變量的聲明格式為&#xff1a;數據類型 *指針變量名…

DeepSeek R1生成圖片總結2(雖然本身是不能直接生成圖片,但是可以想辦法利用別的工具一起實現)

DeepSeek官網 目前階段&#xff0c;DeepSeek R1是不能直接生成圖片的&#xff0c;但可以通過優化文本后轉換為SVG或HTML代碼&#xff0c;再保存為圖片。另外&#xff0c;Janus-Pro是DeepSeek的多模態模型&#xff0c;支持文生圖&#xff0c;但需要本地部署或者使用第三方工具。…

什么是Dubbo?Dubbo框架知識點,面試題總結

本篇包含什么是Dubbo&#xff0c;Dubbo的實現原理&#xff0c;節點角色說明&#xff0c;調用關系說明&#xff0c;在實際開發的場景中應該如何選擇RPC框架&#xff0c;Dubbo的核心架構&#xff0c;Dubbo的整體架構設計及分層。 主頁還有其他的面試資料&#xff0c;有需要的可以…

kafka消費能力壓測:使用官方工具

背景 在之前的業務場景中&#xff0c;我們發現Kafka的實際消費能力遠低于預期。盡管我們使用了kafka-go組件并進行了相關測試&#xff0c;測試情況見《kafka-go:性能測試》這篇文章。但并未能準確找出消費能力低下的原因。 我們曾懷疑這可能是由我的電腦網絡帶寬問題或Kafka部…

【大學生職業規劃大賽備賽PPT資料PDF | 免費共享】

自取鏈接&#xff1a; 鏈接&#xff1a;https://pan.quark.cn/s/4fa45515325e &#x1f4e2; 同學&#xff0c;你是不是正在為職業規劃大賽發愁&#xff1f; 想展示獨特思路卻不知如何下手&#xff1f; 想用專業模板卻找不到資源&#xff1f; 別擔心&#xff01;我整理了全網…

ubuntu20動態修改ip,springboot中yaml的內容的讀取,修改,寫入

文章目錄 前言引入包yaml原始內容操作目標具體代碼執行查看結果總結: 前言 之前有個需求&#xff0c;動態修改ubuntu20的ip&#xff0c;看了下&#xff1a; 本質上是修改01-netcfg.yaml文件&#xff0c;然后執行netplan apply就可以了。 所以&#xff0c;需求就變成了 如何對ya…

【算法】雙指針(下)

目錄 查找總價格為目標值的兩個商品 暴力解題 雙指針解題 三數之和 雙指針解題(左右指針) 四數之和 雙指針解題 雙指針關鍵點 注意事項 查找總價格為目標值的兩個商品 題目鏈接&#xff1a;LCR 179. 查找總價格為目標值的兩個商品 - 力扣&#xff08;LeetCode&#x…

Windows 圖形顯示驅動開發-IoMmu 模型

輸入輸出內存管理單元 (IOMMU) 是一個硬件組件&#xff0c;它將支持具有 DMA 功能的 I/O 總線連接到系統內存。 它將設備可見的虛擬地址映射到物理地址&#xff0c;使其在虛擬化中很有用。 在 WDDM 2.0 IoMmu 模型中&#xff0c;每個進程都有一個虛擬地址空間&#xff0c;即&a…

軟件測評報告包括哪些內容?第三方軟件測評機構推薦

在當今信息技術飛速發展的時代&#xff0c;軟件的品質與性能直接影響到企業的運營效率和市場競爭力。為了確保軟件的可用性和可靠性&#xff0c;軟件測評成為一個不可或缺的環節&#xff0c;軟件測評報告也是對軟件產品進行全面評估后形成的一份文檔&#xff0c;旨在系統地紀錄…

深淺拷貝區別,怎么區別使用

在 JavaScript 中&#xff0c;深拷貝&#xff08;Deep Copy&#xff09; 和 淺拷貝&#xff08;Shallow Copy&#xff09; 是兩種不同的對象復制方式&#xff0c;它們的區別主要體現在對嵌套對象的處理上。以下是它們的詳細對比及使用場景&#xff1a; 1. 淺拷貝&#xff08;Sh…

tailscale + derp中繼 + 阿里云服務器 (無域名版)

使用tailscale默認的中轉節點延遲很高&#xff0c;因為服務器都在國外。 感謝大佬提供的方案&#xff1a;Tailscale 搭建derp中繼節點&#xff0c;不需要域名&#xff0c;不需要備案&#xff0c;不需要申請證書&#xff08;最新&#xff09; - yafeng - 博客園 基于這個方案&…

【異常錯誤】pycharm debug view變量的時候顯示不全,中間會以...顯示

異常問題&#xff1a; 這個是在新版的pycharm中出現的&#xff0c;出現的問題&#xff0c;點擊view后不全部顯示&#xff0c;而是以...折疊顯示 在setting中這么設置一下就好了&#xff1a; 解決辦法&#xff1a; https://youtrack.jetbrains.com/issue/PY-75568/Large-stri…

【DeepSeek系列】04 DeepSeek-R1:帶有冷啟動的強化學習

文章目錄 1、簡介2、主要改進點3、兩個重要觀點4、四階段后訓練詳細步驟4.1 冷啟動4.2 推理導向的強化學習4.3 拒絕采樣和有監督微調4.4 針對所有場景的強化學習 5、蒸餾與強化學習對比6、評估6.1 DeepSeek-R1 評估6.2 蒸餾模型評估 7、結論8、局限性與未來方向 1、簡介 DeepS…

車載音頻配置(二)

目錄 OEM 自定義的車載音頻上下文 動態音頻區配置 向前兼容性 Android 14 車載音頻配置 在 Android 14 中,AAOS 引入了 OEM 插件服務,使你可以更主動地管理由車載音頻服務監督的音頻行為。 隨著新的插件服務的引入,車載音頻配置文件中添加了以下更改: ? OEM 自定義的車…