OpenGL 3D編程大師基礎之路:從幾何體到物理引擎

引言:開啟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…