引言:开启3D编程之旅

欢迎来到令人兴奋的3D编程世界!本教程将带您从OpenGL基础开始,逐步掌握3D渲染的核心技术,最终实现一个包含物理模拟的完整3D场景。我们将探索几何体创建、光照系统、纹理映射、变换操作和碰撞检测等关键主题。

OpenGL 3D开发全景架构图

核心开发流程图(带视觉元素) 

 几何体创建流程

渲染管线(OpenGL 4.0+)

 

. 碰撞检测系统 

3D编程资源地图

 

 

这个完整的流程图和架构图展示了现代OpenGL 3D开发的完整流程,从初始化到高级渲染技术,涵盖了:

  1. 几何核心:参数化几何体创建与复杂模型加载

  2. 渲染管线:从顶点处理到帧缓冲的完整流程

  3. 物理系统:刚体动力学与碰撞检测的集成

  4. 材质系统:PBR材质与纹理映射

  5. 性能优化:多层次优化策略

  6. 场景管理:对象变换与相机控制

每个部分都有对应的视觉表示,帮助理解3D开发的完整生命周期和各个组件之间的关系。

好了,说完上面整个流程,下面我们开始从基础学习开始吧

基础准备:OpenGL环境搭建

依赖库

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <stb_image.h>
#include <vector>
#include <iostream>
 

初始化窗口

int main() {// 初始化GLFWif (!glfwInit()) {std::cerr << "Failed to initialize GLFW" << std::endl;return -1;}// 创建窗口GLFWwindow* window = glfwCreateWindow(1200, 800, "3D编程大师之路", nullptr, nullptr);if (!window) {std::cerr << "Failed to create GLFW window" << std::endl;glfwTerminate();return -1;}glfwMakeContextCurrent(window);// 初始化GLEWif (glewInit() != GLEW_OK) {std::cerr << "Failed to initialize GLEW" << std::endl;return -1;}// 设置视口glViewport(0, 0, 1200, 800);// 主渲染循环while (!glfwWindowShouldClose(window)) {// 清除颜色缓冲和深度缓冲glClearColor(0.1f, 0.1f, 0.1f, 1.0f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// 交换缓冲区和轮询事件glfwSwapBuffers(window);glfwPollEvents();}glfwTerminate();return 0;
}
 

几何体创建:从基础到复杂

1. 立方体(正六面体)

std::vector<float> createCube(float size = 1.0f) {float half = size / 2.0f;return {// 位置              // 法线            // 纹理坐标// 前面-half, -half,  half,  0.0f, 0.0f, 1.0f,  0.0f, 0.0f,half, -half,  half,  0.0f, 0.0f, 1.0f,  1.0f, 0.0f,half,  half,  half,  0.0f, 0.0f, 1.0f,  1.0f, 1.0f,-half,  half,  half,  0.0f, 0.0f, 1.0f,  0.0f, 1.0f,// 后面-half, -half, -half,  0.0f, 0.0f,-1.0f,  0.0f, 0.0f,// ... 完整实现需要36个顶点};
}
 

2. 球体(UV球体)

std::vector<float> createSphere(float radius = 1.0f, int sectors = 36, int stacks = 18) {std::vector<float> vertices;const float PI = acos(-1);float sectorStep = 2 * PI / sectors;float stackStep = PI / stacks;for (int i = 0; i <= stacks; ++i) {float stackAngle = PI / 2 - i * stackStep;float xy = radius * cosf(stackAngle);float z = radius * sinf(stackAngle);for (int j = 0; j <= sectors; ++j) {float sectorAngle = j * sectorStep;float x = xy * cosf(sectorAngle);float y = xy * sinf(sectorAngle);// 位置vertices.push_back(x);vertices.push_back(y);vertices.push_back(z);// 法线glm::vec3 normal = glm::normalize(glm::vec3(x, y, z));vertices.push_back(normal.x);vertices.push_back(normal.y);vertices.push_back(normal.z);// 纹理坐标float s = (float)j / sectors;float t = (float)i / stacks;vertices.push_back(s);vertices.push_back(t);}}return vertices;
}
 

3. 圆柱体

std::vector<float> createCylinder(float radius = 0.5f, float height = 1.0f, int sectors = 36) {std::vector<float> vertices;const float PI = acos(-1);float sectorStep = 2 * PI / sectors;// 侧面for (int i = 0; i <= sectors; ++i) {float angle = i * sectorStep;float x = cosf(angle);float z = sinf(angle);// 底部顶点vertices.push_back(radius * x);vertices.push_back(-height/2);vertices.push_back(radius * z);vertices.push_back(x);vertices.push_back(0.0f);vertices.push_back(z);vertices.push_back((float)i / sectors);vertices.push_back(0.0f);// 顶部顶点vertices.push_back(radius * x);vertices.push_back(height/2);vertices.push_back(radius * z);vertices.push_back(x);vertices.push_back(0.0f);vertices.push_back(z);vertices.push_back((float)i / sectors);vertices.push_back(1.0f);}// 顶部和底部圆盘// ... 实现省略return vertices;
}
 

4. 胶囊体(圆柱+半球)

std::vector<float> createCapsule(float radius = 0.5f, float height = 1.0f, int sectors = 36) {std::vector<float> vertices;// 创建圆柱体(中间部分)auto cylinder = createCylinder(radius, height, sectors);vertices.insert(vertices.end(), cylinder.begin(), cylinder.end());// 创建顶部半球auto topSphere = createSphere(radius, sectors, sectors/2);// 平移并添加到顶点for (size_t i = 0; i < topSphere.size(); i += 8) {topSphere[i+1] += height/2; // Y坐标上移vertices.push_back(topSphere[i]);vertices.push_back(topSphere[i+1]);vertices.push_back(topSphere[i+2]);vertices.push_back(topSphere[i+3]);vertices.push_back(topSphere[i+4]);vertices.push_back(topSphere[i+5]);vertices.push_back(topSphere[i+6]);vertices.push_back(topSphere[i+7]);}// 创建底部半球// ... 类似顶部半球但下移return vertices;
}
 

着色器编程:点亮3D世界

顶点着色器

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

片段着色器(Phong光照模型)

#version 330 core
out vec4 FragColor;in vec3 FragPos;
in vec3 Normal;
in vec2 TexCoords;uniform sampler2D texture_diffuse;
uniform vec3 lightPos;
uniform vec3 viewPos;
uniform vec3 lightColor;void main() {// 环境光float ambientStrength = 0.1;vec3 ambient = ambientStrength * lightColor;// 漫反射vec3 norm = normalize(Normal);vec3 lightDir = normalize(lightPos - FragPos);float diff = max(dot(norm, lightDir), 0.0);vec3 diffuse = diff * lightColor;// 镜面反射float 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) * texture(texture_diffuse, TexCoords).rgb;FragColor = vec4(result, 1.0);
}
 

纹理映射:赋予物体表面细节

unsigned int loadTexture(const char* path) {unsigned int textureID;glGenTextures(1, &textureID);int width, height, nrComponents;unsigned char* data = stbi_load(path, &width, &height, &nrComponents, 0);if (data) {GLenum format;if (nrComponents == 1)format = GL_RED;else if (nrComponents == 3)format = GL_RGB;else if (nrComponents == 4)format = GL_RGBA;glBindTexture(GL_TEXTURE_2D, textureID);glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);glGenerateMipmap(GL_TEXTURE_2D);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);stbi_image_free(data);} else {std::cerr << "Texture failed to load at path: " << path << std::endl;stbi_image_free(data);}return textureID;
}
 

变换操作:移动、旋转与缩放

class Transform {
public:glm::vec3 position = glm::vec3(0.0f);glm::vec3 rotation = glm::vec3(0.0f); // 欧拉角glm::vec3 scale = glm::vec3(1.0f);glm::mat4 getModelMatrix() const {glm::mat4 model = glm::mat4(1.0f);model = glm::translate(model, position);model = glm::rotate(model, glm::radians(rotation.x), glm::vec3(1.0f, 0.0f, 0.0f));model = glm::rotate(model, glm::radians(rotation.y), glm::vec3(0.0f, 1.0f, 0.0f));model = glm::rotate(model, glm::radians(rotation.z), glm::vec3(0.0f, 0.0f, 1.0f));model = glm::scale(model, scale);return model;}void move(const glm::vec3& direction, float speed) {position += direction * speed;}void rotate(float angle, const glm::vec3& axis) {rotation += axis * angle;}void resize(const glm::vec3& factor) {scale *= factor;}
};
 

碰撞检测:物理交互基础

轴对齐包围盒(AABB)碰撞检测

struct AABB {glm::vec3 min;glm::vec3 max;AABB(glm::vec3 min, glm::vec3 max) : min(min), max(max) {}bool intersects(const AABB& other) const {return (min.x <= other.max.x && max.x >= other.min.x) &&(min.y <= other.max.y && max.y >= other.min.y) &&(min.z <= other.max.z && max.z >= other.min.z);}void update(const Transform& transform) {// 根据变换更新包围盒glm::vec3 center = transform.position;glm::vec3 halfSize = transform.scale * 0.5f; // 假设原始物体是单位大小的min = center - halfSize;max = center + halfSize;}
};
 

射线检测(鼠标拾取)

glm::vec3 screenPosToWorldRay(int mouseX, int mouseY, int screenWidth, int screenHeight,const glm::mat4& view, const glm::mat4& projection) 
{// 将鼠标位置转换为标准化设备坐标float x = (2.0f * mouseX) / screenWidth - 1.0f;float y = 1.0f - (2.0f * mouseY) / screenHeight;float z = 1.0f;// 齐次裁剪坐标glm::vec4 rayClip = glm::vec4(x, y, -1.0f, 1.0f);// 转换为观察空间glm::vec4 rayEye = glm::inverse(projection) * rayClip;rayEye = glm::vec4(rayEye.x, rayEye.y, -1.0f, 0.0f);// 转换为世界空间glm::vec3 rayWorld = glm::vec3(glm::inverse(view) * rayEye);rayWorld = glm::normalize(rayWorld);return rayWorld;
}bool rayIntersectsSphere(glm::vec3 rayOrigin, glm::vec3 rayDirection,glm::vec3 sphereCenter,float sphereRadius)
{glm::vec3 oc = rayOrigin - sphereCenter;float a = glm::dot(rayDirection, rayDirection);float b = 2.0f * glm::dot(oc, rayDirection);float c = glm::dot(oc, oc) - sphereRadius * sphereRadius;float discriminant = b * b - 4 * a * c;return discriminant >= 0;
}
 

完整场景实现:3D物理沙盒

class PhysicsObject {
public:Transform transform;glm::vec3 velocity = glm::vec3(0.0f);glm::vec3 angularVelocity = glm::vec3(0.0f);float mass = 1.0f;void update(float deltaTime) {// 应用重力velocity += glm::vec3(0.0f, -9.8f, 0.0f) * deltaTime;// 更新位置和旋转transform.position += velocity * deltaTime;transform.rotation += angularVelocity * deltaTime;// 简单的边界碰撞if (transform.position.y < -5.0f) {transform.position.y = -5.0f;velocity.y = -velocity.y * 0.8f; // 弹性系数}}
};int main() {// 初始化代码...// 创建着色器程序Shader shader("vertex.glsl", "fragment.glsl");// 创建几何体auto cube = createCube();auto sphere = createSphere();auto cylinder = createCylinder();auto capsule = createCapsule();// 加载纹理unsigned int marbleTex = loadTexture("marble.jpg");unsigned int metalTex = loadTexture("metal.png");// 创建物理对象std::vector<PhysicsObject> objects;// 创建地面PhysicsObject ground;ground.transform.scale = glm::vec3(20.0f, 0.5f, 20.0f);ground.transform.position = glm::vec3(0.0f, -5.0f, 0.0f);objects.push_back(ground);// 主循环while (!glfwWindowShouldClose(window)) {float currentFrame = glfwGetTime();float deltaTime = currentFrame - lastFrame;lastFrame = currentFrame;// 处理输入processInput(window, deltaTime);// 更新物理for (auto& obj : objects) {obj.update(deltaTime);}// 碰撞检测for (size_t i = 0; i < objects.size(); ++i) {for (size_t j = i + 1; j < objects.size(); ++j) {if (checkCollision(objects[i], objects[j])) {resolveCollision(objects[i], objects[j]);}}}// 渲染glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);shader.use();// 设置光照shader.setVec3("lightPos", lightPos);shader.setVec3("viewPos", camera.Position);shader.setVec3("lightColor", 1.0f, 1.0f, 1.0f);// 设置视图/投影矩阵glm::mat4 view = camera.GetViewMatrix();glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), 1200.0f/800.0f, 0.1f, 100.0f);shader.setMat4("view", view);shader.setMat4("projection", projection);// 渲染对象for (const auto& obj : objects) {glm::mat4 model = obj.transform.getModelMatrix();shader.setMat4("model", model);// 根据对象类型绑定不同纹理和渲染不同几何体if (&obj == &ground) {glBindTexture(GL_TEXTURE_2D, marbleTex);renderMesh(cubeMesh);} else {glBindTexture(GL_TEXTURE_2D, metalTex);renderMesh(sphereMesh); // 或其他几何体}}// 交换缓冲区和轮询事件glfwSwapBuffers(window);glfwPollEvents();}// 清理资源...return 0;
}
 

性能优化与高级技巧

1. 实例化渲染

// 准备实例化数据
std::vector<glm::mat4> modelMatrices;
for (int i = 0; i < amount; ++i) {glm::mat4 model = glm::mat4(1.0f);// 设置模型矩阵...modelMatrices[i] = model;
}// 创建实例化数组
unsigned int instanceVBO;
glGenBuffers(1, &instanceVBO);
glBindBuffer(GL_ARRAY_BUFFER, instanceVBO);
glBufferData(GL_ARRAY_BUFFER, amount * sizeof(glm::mat4), &modelMatrices[0], GL_STATIC_DRAW);// 设置顶点属性指针
glBindVertexArray(VAO);
// 设置mat4属性需要4个顶点属性
glEnableVertexAttribArray(3); 
glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)0);
glEnableVertexAttribArray(4); 
glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(sizeof(glm::vec4)));
// ... 类似设置属性5和6// 设置实例化除法率
glVertexAttribDivisor(3, 1);
glVertexAttribDivisor(4, 1);
glVertexAttribDivisor(5, 1);
glVertexAttribDivisor(6, 1);// 渲染
glDrawElementsInstanced(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, 0, amount);
 

2. 帧缓冲与后期处理

// 创建帧缓冲
unsigned int framebuffer;
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);// 创建纹理附件
unsigned int textureColorbuffer;
glGenTextures(1, &textureColorbuffer);
glBindTexture(GL_TEXTURE_2D, textureColorbuffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1200, 800, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureColorbuffer, 0);// 渲染到帧缓冲
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// ... 渲染场景// 回到默认帧缓冲并进行后期处理
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT);
postProcessingShader.use();
glBindVertexArray(quadVAO);
glDisable(GL_DEPTH_TEST);
glBindTexture(GL_TEXTURE_2D, textureColorbuffer);
glDrawArrays(GL_TRIANGLES, 0, 6);
 

结语:通往3D大师之路

通过本教程,您已经掌握了OpenGL 3D编程的核心技术:

  1. 几何体创建:立方体、球体、圆柱体和胶囊体

  2. 渲染管线:着色器编程、纹理映射和光照模型

  3. 变换操作:移动、旋转和缩放物体

  4. 物理模拟:碰撞检测、射线检测和简单物理系统

  5. 性能优化:实例化渲染和后期处理

这些技术构成了现代3D应用的基础框架。要进一步深造,可以探索:

  • 骨骼动画与蒙皮技术

  • 基于物理的渲染(PBR)

  • 高级光照技术(阴影、全局光照)

  • 粒子系统和流体模拟

  • 地形生成与LOD技术

3D编程是一个不断发展的领域,持续学习和实践是成为大师的关键。祝您在3D编程的旅程中不断突破,创造出令人惊叹的虚拟世界!

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

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

相关文章

解决往GitHub提交大文件报错问题

前言 GitHub仓库单个文件的推荐大小不能超过50MB&#xff08;仅限于警告&#xff09;&#xff0c;但绝对不能超过100MB&#xff08;拒绝提交&#xff09; 问题 人总有手贱的时候&#xff0c;一不小心往Git仓库拷贝大文件并尝试push到GitHub&#xff0c;发现报错后才意识到问…

PostgreSQL基于归档日志的持续恢复测试

测试环境&#xff1a; os: linux PG: 17.4 src ip: 192.168.100.51 dst ip: 192.168.100.138 src: PGDATA/home/postgres174/pgdata dst: PGDATA/data/174/pgdata_standby 归档路径&#xff1a; 192.168.100.138 /data/174/archivedir 测试流程&#xff1a; 1. 主库(…

Linux——内核——网络协议

Linux网络协议栈是Linux内核中实现网络通信的核心组件&#xff0c;其设计遵循分层架构&#xff0c;支持多种网络协议和功能。以下从协议栈的分层结构、关键组件、工作流程、数据包处理机制、优化与调试等方面进行详尽阐述&#xff1a; 一、协议栈的分层结构 Linux网络协议栈基…

vue | 插件 | 移动文件的插件 —— move-file-cli 插件 的安装与使用

问题&#xff1a;想将打包生成的 dist 文件下的样式相关文件&#xff0c;进行移动。 解决&#xff1a;在 npm 上找写好的兼容操作系统的包 move-file-cli 插件 &#xff0c;用于移动文件 move-file-cli 插件的安装与使用 安装&#xff1a;npm install move-file-cli --save-d…

多个单片机简单通讯框架

文章目录 一、场景描述二、框架搭建设计思路通信协议设计2号单片机通讯框架框架优化建议 三、2号单片机的通讯框架如何处理消息丢失和重传&#xff1f;消息丢失与重传机制设计改进的通信协议重传机制实现关键机制说明优化建议 一、场景描述 有3个单片机进行通讯&#xff0c;分…

如何在服务区已有预装镜像的情况下管理自己的包

你的需求非常明确&#xff1a;希望利用 NGC 镜像预装的主环境包&#xff08;如 PyTorch、CUDA&#xff09;&#xff0c;同时能独立管理自己额外安装的包&#xff0c;避免直接污染主环境。以下是几种解决方案&#xff0c;按推荐度排序&#xff1a; 方案 1&#xff1a;虚拟环境复…

JavaWeb之Servlet(2)RequestResponse..

文章目录 1 Request和Response的概述2 Request对象2.1 Request继承体系2.2 Request获取请求数据2.2.1 获取请求行数据2.2.2 获取请求头数据2.2.3 获取请求体数据1-3小结2.2.4 获取请求参数的通用方式请求参数和请求数据的区别问题案例分析问题解决 2.3 IDEA快速创建Servlet2.4 …

将 h264+g711a存为 mp4文件,记录

将 h264g711a存为 mp4文件&#xff0c;记录 &#x1f4cc; 关键问题&#xff1a;MP4 不原生支持 G.711A MP4 容器格式 不原生支持 G.711&#xff08;包括 A-law&#xff0c;也就是 G.711A&#xff09;音频&#xff0c;所以不能直接将 G.711A 音频封装进 MP4 文件中。常见的做法…

【Elasticsearch】全文检索 组合检索

全文检索 1.全文检索1.1 准备测试数据1.2 案例分析1.2.1 match&#xff08;分词检索&#xff09;1.2.2 match_phrase&#xff08;短语检索&#xff09;1.2.3 match_phrase_prefix&#xff08;短语前缀匹配&#xff09;1.2.4 multi_match&#xff08;多字段匹配&#xff09;1.2.…

信号处理学习——文献精读与code复现之TFN——嵌入时频变换的可解释神经网络(上)

​​​​​​​​​​​​​​TFN: An interpretable neural network with time-frequency transform embedded for intelligent fault diagnosis - ScienceDirecthttps://www.sciencedirect.com/science/article/abs/pii/S0888327023008609?via%3Dihub &#xff08;看看玲娜贝…

Panda3D实战:从入门到精通

Panda3D基础实例 创建一个简单的Panda3D场景,加载一个模型并显示: from direct.showbase.ShowBase import ShowBaseclass MyApp(ShowBase):def __init__(self):ShowBase.__init__(self)self.scene = self.loader.loadModel("models/environment")self.scene.repa…

Galera集群:高可用MySQL同步复制方案

目录 Galera Cluster 概述 核心架构与组件 WSREP API Group Communication System (GCP) 同步复制机制 复制流程详解 冲突检测算法 关键特性 多主架构实现 强一致性保障 自动成员管理 性能优化策略 并行复制实现 流控机制详解 批处理与压缩 部署与监控 详细配…

MybatisPlus-03.快速入门-常用注解

一.MP的原理 mp究竟是如何知道我们需要对哪个表进行操作&#xff0c;并且又是如何知道要操作哪些字段的呢&#xff1f;这是因为mp使用到了反射机制&#xff0c;我们在定义mapper接口时使其继承了BaseMapper接口&#xff0c;并指定了BaseMapper接口泛型为User&#xff0c;因此m…

ABAP+记录一个BDC的BUG修改过程

问题背景&#xff1a; 业务顾问反馈在使用BDC 进行MEQ1进行供应商配额时&#xff0c;由于以前录屏时用例只有3行数据&#xff0c;导致现在有5行数据的时候&#xff0c;代码仍然只获取了3行数据进行录入&#xff0c;现在需要更改代码&#xff0c;使其按照实际情况自动调整行数。…

github上传代码步骤(http)

github上传步骤&#xff08;http&#xff09; 之前github上传不了代码&#xff0c;总是报错。后面发现自己用的ssh上传需要秘钥&#xff0c;现在我介绍一个最简单的http上传方法&#xff08;虽然没有ssh安全。。。但简单嘛~&#xff09;&#xff0c;现在我做个例子&#xff0c…

深入理解Nginx-以实际http通信例子改造带ssl配Nginx的实战-优雅草卓伊凡|麻子

深入理解Nginx-以实际http通信例子改造带ssl配Nginx的实战-优雅草卓伊凡|麻子 SSL/TLS在Nginx中的底层实现原理 Nginx的SSL模块架构 Nginx通过ngx_http_ssl_module模块实现SSL/TLS功能&#xff0c;该模块基于OpenSSL库构建。根据Nginx官方文档&#xff0c;SSL模块在Nginx架构…

AT6558R-5N32介绍

作为单芯片SOC方案&#xff0c;AT6558R在片上整合了射频前端、数字基带处理器与32位RISC CPU&#xff0c;并具备电源管理能力。该芯片兼容北斗、GPS、GLONASS三大卫星导航系统&#xff0c;可实现多模协同定位‌。 主要特征 支持 BDS/GPS/GLONASS 多系统联合定位 和单系统独立定…

“对象创建”模式之原型模式

目录 Prototype 原型模式动机 Motivation引例模式定义结构 Structure要点总结 Prototype 原型模式 动机 Motivation 在软件系统中&#xff0c;经常面临着“某些结构复杂的对象”的创建工作&#xff1b;由于需求的变化&#xff0c;这些对象经常面临着剧烈的变化&#xff0c;但…

Tomcat服务概述

前言&#xff1a; 作为Apache软件基金会Jakarta项目的核心成果&#xff0c;Tomcat凭借其轻量级、开源免费的特性&#xff0c;已成为Java Web应用服务的行业基准。它实现了完整的Servlet与JSP规范&#xff0c;通过模块化架构&#xff08;Connector请求处理层与Container业务逻辑…

HarmonyOS应用开发高级认证知识点梳理 (一) 布局与样式

以下是 HarmonyOS 应用开发中 ‌布局与样式‌ 的核心知识点梳理&#xff08;针对高级认证备考&#xff09;&#xff0c;结合官方文档与高频考点&#xff1a; 一、布局系统核心知识点 布局容器类型‌ 线性布局‌&#xff1a;Column&#xff08;纵向&#xff09;、Row&#xf…