文章目录

  • 【OpenGL学习】(六)图形添加纹理
    • 纹理环绕
    • 纹理过滤
    • 纹理颜色与顶点颜色混合

OpenGL纹理介绍:https://learnopengl-cn.github.io/01%20Getting%20started/06%20Textures/

【OpenGL学习】(六)图形添加纹理

项目链接:https://github.com/BinaryAI-1024/OpenGLPorjects/blob/master/textures


filesystem.h用于获取图像路径;stb_image.h用于加载图像。
顶点着色器texture.vs:

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aTexCoord;out vec3 ourColor;
out vec2 TexCoord;void main()
{gl_Position = vec4(aPos, 1.0);ourColor = aColor;TexCoord = vec2(aTexCoord.x, aTexCoord.y);
}

片段着色器texture.fs:

#version 330 core
out vec4 FragColor;in vec3 ourColor;
in vec2 TexCoord;// texture sampler
uniform sampler2D texture1;void main()
{FragColor = texture(texture1, TexCoord);
}

textures.cpp实现纹理图映射到正方形上:

// textures.cpp
#include <glad/glad.h>  
#include <GLFW/glfw3.h>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"  // 包含 STB 图像加载库,用于加载纹理图像
#include <filesystem.h> 
#include <shader_s.h>   
#include <iostream>     void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
const unsigned int WRAP_TYPE = 1;
const unsigned int FILTER_TYPE = 2;int main()
{glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); #ifdef __APPLE__glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif// 创建 GLFW 窗口GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL); if (window == NULL){std::cout << "Failed to create GLFW window" << std::endl; glfwTerminate(); return -1;}glfwMakeContextCurrent(window); glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);// 初始化 GLADif (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {std::cout << "Failed to initialize GLAD" << std::endl; return -1;}Shader ourShader("texture.vs", "texture.fs"); // 创建着色器对象// 设置顶点数据(和缓冲区)并配置顶点属性//float vertices[] = {//    // 位置坐标          // 颜色           // 纹理坐标//     0.5f,  0.5f, 0.0f,   1.0f, 0.0f, 0.0f,   2.0f, 2.0f, // 右上角//     0.5f, -0.5f, 0.0f,   0.0f, 1.0f, 0.0f,   2.0f, -1.0f, // 右下角//    -0.5f, -0.5f, 0.0f,   0.0f, 0.0f, 1.0f,   -1.0f, -1.0f, // 左下角//    -0.5f,  0.5f, 0.0f,   1.0f, 1.0f, 0.0f,   -1.0f, 2.0f  // 左上角 //};float vertices[] = {// 位置坐标          // 颜色           // 纹理坐标(翻转y轴)0.5f,  0.5f, 0.0f,   1.0f, 0.0f, 0.0f,   1.0f, 0.0f, // 右上角0.5f, -0.5f, 0.0f,   0.0f, 1.0f, 0.0f,   1.0f, 1.0f, // 右下角-0.5f, -0.5f, 0.0f,   0.0f, 0.0f, 1.0f,   0.0f, 1.0f, // 左下角-0.5f,  0.5f, 0.0f,   1.0f, 1.0f, 0.0f,   0.0f, 0.0f  // 左上角 };unsigned int indices[] = {0, 1, 3, // 第一个三角形1, 2, 3  // 第二个三角形};// 定义顶点缓冲对象、顶点数组对象和元素缓冲对象unsigned int VBO, VAO, EBO; glGenVertexArrays(1, &VAO); // 生成顶点数组对象glGenBuffers(1, &VBO);     // 生成顶点缓冲对象glGenBuffers(1, &EBO);     // 生成元素缓冲对象glBindVertexArray(VAO); // 绑定顶点数组对象glBindBuffer(GL_ARRAY_BUFFER, VBO); // 绑定顶点缓冲对象glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // 将顶点数据复制到缓冲区glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); // 绑定元素缓冲对象glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); // 将索引数据复制到缓冲区// 设置顶点属性指针:xyz(顶点坐标)rgb(顶点颜色)st(纹理坐标)glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0); // 设置位置属性指针glEnableVertexAttribArray(0); // 启用位置属性glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float))); // 设置颜色属性指针glEnableVertexAttribArray(1); // 启用颜色属性// 纹理坐标属性glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float))); // 设置纹理坐标属性指针glEnableVertexAttribArray(2); // 启用纹理坐标属性// 加载并创建纹理unsigned int texture; // 定义纹理对象glGenTextures(1, &texture); // 生成纹理对象glBindTexture(GL_TEXTURE_2D, texture); // 绑定纹理对象,所有 GL_TEXTURE_2D 操作对该纹理生效//  设置 S 轴和T轴的纹理环绕方式if (WRAP_TYPE == 1) {glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);}else if (WRAP_TYPE == 2) {glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);}else if (WRAP_TYPE == 3) {glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);}else if (WRAP_TYPE == 4) {// 如果选择GL_CLAMP_TO_BORDER纹理环绕,需要设置边缘颜色float borderColor[] = { 1.0f, 0.0f, 0.0f, 1.0f }; // 红色glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);}if (FILTER_TYPE == 1) {glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // 设置纹理缩小过滤方式glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // 设置纹理放大过滤方式}else if (FILTER_TYPE == 2) {glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); }else if (FILTER_TYPE == 3) {glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);}else if (FILTER_TYPE == 4) {glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);}else if (FILTER_TYPE == 5) {glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);}else if (FILTER_TYPE == 6) {glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);}// 加载图像,创建纹理并生成 Mipmapint width, height, nrChannels; // 定义图像宽度、高度和通道数std::string imagePath = FileSystem::getPath("resources/grid2.jpg");std::cout << "Attempting to load texture from: " << imagePath << std::endl; unsigned char* data = stbi_load(imagePath.c_str(), &width, &height, &nrChannels, 0); // 加载图像数据if (data){// 将图像数据上传到纹理glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); glGenerateMipmap(GL_TEXTURE_2D); // 生成 Mipmap}else{std::cout << "Failed to load texture" << std::endl; }stbi_image_free(data); // 释放图像数据// 渲染循环while (!glfwWindowShouldClose(window)) {processInput(window); // 渲染glClearColor(0.2f, 0.3f, 0.3f, 1.0f); // 设置清屏颜色glClear(GL_COLOR_BUFFER_BIT); // 清空颜色缓冲// 绑定纹理对象glBindTexture(GL_TEXTURE_2D, texture); // 渲染容器ourShader.use(); // 使用着色器程序glBindVertexArray(VAO); // 绑定顶点数组对象glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); // 绘制三角形glfwSwapBuffers(window);glfwPollEvents();}glDeleteVertexArrays(1, &VAO);glDeleteBuffers(1, &VBO);     glDeleteBuffers(1, &EBO);    glfwTerminate(); return 0;
}void processInput(GLFWwindow* window)
{if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) glfwSetWindowShouldClose(window, true); 
}void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{glViewport(0, 0, width, height); 
}

纹理环绕

纹理图像(纹理像素组成):
在这里插入图片描述

图形的纹理坐标的范围通常是从(0, 0)到(1, 1),如果把纹理坐标设置在这个范围之外,那么就需要指定纹理环绕方式对超过的部分进行填充。OpenGL提供以下四种方式:

  • GL_REPEAT :重复纹理图像,为默认方法。
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

  • GL_MIRRORED_REPEAT:镜像重复
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);

在这里插入图片描述

  • GL_CLAMP_TO_EDGE:纹理坐标会被约束在0到1之间,超出的部分会重复纹理的边缘。
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

在这里插入图片描述

  • GL_CLAMP_TO_BORDER:边界颜色填充 ,超出的坐标为指定的边缘颜色。
     // 如果选择GL_CLAMP_TO_BORDER纹理环绕,需要设置边缘颜色float borderColor[] = { 1.0f, 0.0f, 0.0f, 1.0f }; // 红色glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);

纹理过滤

图形和纹理图像的形状和大小不一定完全匹配,因此需要对纹理图像的像素进行过滤。OpenGL的纹理过滤是一种通过插值或采样技术优化纹理映射效果的方法,用于解决纹理在放大、缩小或斜视角渲染时出现的失真、锯齿或模糊问题,提升渲染质量。一般通过最近邻和线性插值实现。

以对下面的纹理图进行放大为例,
在这里插入图片描述

  • GL_NEAREST: 直接选取与纹理坐标最邻近的纹理像素颜色。

在这里插入图片描述
GL_LINEAR:对纹理坐标附近的纹理像素进行插值,近似出这些纹理像素之间的颜色。

在这里插入图片描述

在缩小过滤时,由于远处的物体在屏幕上的投影面积较小,可能仅占用极少的片段(屏幕像素)。此时,OpenGL需要从高分辨率纹理中为这些片段获取颜色值,但由于单个片段需要覆盖纹理中的一大片区域(多个Texel),直接采样高分辨率纹理会导致严重的采样不足问题。
具体表现为:GPU可能仅从该区域中选取一个或少数几个Texel的颜色值,从而丢失了纹理的高频细节,最终在屏幕上产生锯齿、闪烁或摩尔纹等视觉伪影。

以下面的纹理图为例,

对其进行缩小:

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 


可以看到,视角中远处的像素出现较大失真。

多级渐远纹理(MIPMAP)通过预生成一系列不同分辨率的纹理副本(从原始纹理到最低分辨率),使GPU能够根据片段覆盖的纹理区域大小,动态择最合适的分辨率级别进行采样,从而避免采样不足的问题。OpenGL提供了以下四种基于多级渐远纹理的过滤方法:

  • GL_NEAREST_MIPMAP_NEAREST:首先,根据当前片段(屏幕像素)覆盖的纹理区域大小,选择最接近的MIPMAP级别(即分辨率最匹配的那一级)。然后,在该MIPMAP级别中,直接使用最邻近的纹理像素(Texel)颜色(不进行插值)。

  • GL_LINEAR_MIPMAP_NEAREST:首先,选择最接近的MIPMAP级别。然后,在该MIPMAP级别中,对纹理坐标进行线性插值(即取周围4个纹理像素的加权平均值)。

  • GL_NEAREST_MIPMAP_LINEAR:首先,找到两个最匹配当前片段覆盖大小的MIPMAP级别(例如,一个略大,一个略小)。然后,在这两个MIPMAP级别中,分别使用最邻近的纹理像素颜色。最后,对这两个级别的采样结果进行线性插值(即加权平均)。

  • GL_LINEAR_MIPMAP_LINEAR:首先,找到两个最匹配当前片段覆盖大小的MIPMAP级别。然后,在这两个MIPMAP级别中,分别对纹理坐标进行线性插值。最后,对这两个级别的线性插值结果再进行线性插值(即双重加权平均)。

以第四种方法为例:

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // 放大不需要采用MIPMAP

在这里插入图片描述
可以看到,渲染效果比普通的方法更好。

纹理颜色与顶点颜色混合

修改片段着色器:

#version 330 core
out vec4 FragColor;in vec3 ourColor;
in vec2 TexCoord;// texture sampler
uniform sampler2D texture1;void main()
{//FragColor = texture(texture1, TexCoord);FragColor = texture(texture1, TexCoord) * vec4(ourColor, 1.0);
}

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

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

相关文章

allure安装

一、安装java 需要安装java环境&#xff0c;不安装的话在运行前会报错下列问题&#xff08;前提是安装了allure未安装java&#xff09; 1.官网地址&#xff1a;https://www.oracle.com/ 2.点击”Download Java“ 3.选择JDK正式版本&#xff08;需要jdk1.8&#xff09; 4.选择W…

SpringBoot基于JavaWeb的城乡居民基本医疗信息管理系统

概述 一个基于SpringBoot框架开发的JavaWeb医疗信息管理系统&#xff0c;采用了现代化的技术架构&#xff0c;功能全面&#xff0c;非常适合作为学习项目或二次开发的基础。 主要内容 该系统主要包含以下核心功能模块&#xff1a; ​​用户管理模块​​ 实现管理员、医生、…

SQL变量声明与赋值 分支 循环

– 变量 分支 循环 – declare 变量名 数据类型 – declare 关键字&#xff0c;作用声明变量 – 变量名&#xff1a;以开头 – 数据类型&#xff1a;数据库中支持的数据类型&#xff1a;int varchar(n) text char(n) nvarchar(n) nchar(n) declare name varchar(255)– 定义多…

AWS S3 可观测性最佳实践

AWS S3 介绍 AWS S3&#xff08;Amazon Simple Storage Service&#xff09;是一种可扩展的对象存储服务&#xff0c;提供高可用性、持久性和安全性。它允许用户存储和检索任意数量的数据&#xff0c;并通过简单的 Web 服务接口访问这些数据。S3 支持多种存储类别&#xff0c;…

Ubuntu下布署mediasoup-demo

一、引言 mediasoup是一个强大的SFU架构的WebRTC流媒体服务器&#xff0c;凭借其多功能性、高性能和可扩展性&#xff0c;mediasoup成为构建多方视频会议和实时流媒体应用程序的完美选择。它具有联播、SVC、传输BWE和更多尖端功能。本文介绍了mediasoup-demo在Ubuntu下的布署。…

【JVS更新日志】物联网、智能排产APS、企业计划、规则引擎6.25更新说明!

项目介绍 JVS是企业级数字化服务构建的基础脚手架&#xff0c;主要解决企业信息化项目交付难、实施效率低、开发成本高的问题&#xff0c;采用微服务配置化的方式&#xff0c;提供了低代码数据分析物联网的核心能力产品&#xff0c;并构建了协同办公、企业常用的管理工具等&…

解决git pull,push 每次操作输入账号密码问题

服务器每次git pull 的时候都需要输入账号密码&#xff0c;一劳永逸解决它。 解决方案&#xff1a; 找到项目下 .git /config 文件&#xff0c;然后打开&#xff0c;编辑 [rootiZbp11b24d3d7nc8uvjx9mZ .git]# ls branches config description FETCH_HEAD HEAD hooks i…

Netty:深入解析AbstractByteBufAllocator架构设计

AbstractByteBufAllocator 类结构分析 类结构概览 public abstract class AbstractByteBufAllocator implements ByteBufAllocator {// 静态常量static final int DEFAULT_INITIAL_CAPACITY 256;static final int DEFAULT_MAX_CAPACITY Integer.MAX_VALUE;// ...其他常量//…

Java 日志管理与分析

为什么需要日志 ■ 发⽣了什么&#xff08;What&#xff09;。 ■ 何时发⽣的&#xff08;When&#xff09;。 ■ 发⽣于何处&#xff08;Where&#xff09;。 ■ 谁参与其中&#xff08;Who&#xff09;。 ■ 参与者来源&#xff08;第⼆个Where&#xff0c;注意与上⾯的Wher…

bmc TrueSight 监控mysql配置

bmc TrueSight 监控mysql配置 1.将pat加入mysql组 useradd pat;echo patpassword|passwd --stdin pat usermod -aG mysql pat2.设置环境变量 查看文件是否存在[rootu1acmsdp01 ~]# find / -name mysql.sock /var/lib/mysql/mysql.sock ^C [rootu1acmsdp01 ~]# cd /var/lib/my…

WinAppDriver 自动化测试:C#篇

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】

zlmediakit webrtc搭建使用

webrtc 编译与使用 | ZLMediaKit 官方文档参考 编译机器&#xff1a; centos 7.6 gcc 版本 10.1.0 (GCC) cmake version 3.23.0web播放rtsp流视频&#xff0c;使用webrtc毫秒级延迟_webrtc播放rtsp流-CSDN博客 依赖准备 openssl 安装 (openssl 版本要求 1.1 以上) 我的…

Linux下使用docker nginx部署vue前端项目工程

1、使用Docker和Nginx部署Vue项目的步骤 1、准备好VUE项目&#xff0c;已打包编译 2、docker环境已完成安装 3、本地环境上创建nginx目录&#xff0c;下包括conf&#xff0c;html&#xff0c;logs目录。用于容器映射&#xff08;其实是方便修改文件&#xff0c;因为在容器中…

从实验室到生产线:机器学习模型部署的七大陷阱及PyTorch Serving避坑指南

1 实验室与生产环境的鸿沟&#xff1a;为什么99%的模型部署会失败&#xff1f; &#xff08;1&#xff09;部署失败的真实数据统计 根据2023年MLOps行业报告&#xff1a; 78%的组织表示模型部署时间超过预期65%的模型部署后性能下降超过20%仅12%的组织能在一周内完成模型更新…

Module not found: Error: Can‘t resolve ‘core-js/modules/es.array.concat.js‘

遇到错误“Module not found: Error: Can’t resolve ‘core-js/modules/es.array.concat.js’”通常是因为你的项目中使用了core-js库&#xff0c;但是你的项目配置或者core-js的版本不支持你正在尝试使用的功能。下面是一些解决这个问题的步骤&#xff1a; 确认core-js版本 …

Windows10中设置多个虚拟IP方法

一.netsh 命令添加&#xff08;最直接、最简单&#xff09; 1.在 Windows 10 中&#xff0c;使用 netsh 命令为现有物理网卡或虚拟网卡添加额外的 IP 地址&#xff08;IP Alias&#xff09;是最直接的方法。这些 IP 地址与主 IP 在同一网段&#xff0c;共享同一张网卡的 MAC 地…

回答 如何通过inode client的SSLVPN登录之后,访问需要通过域名才能打开的服务

需要dns代理 1 配置需求或说明 1.1 适用的产品系列 本案例适用于软件平台为Comware V7系列防火墙&#xff1a;本案例适用于如F5080、F5060、F5030、F5000-M等F5000、F5000-X系列的防火墙。 注&#xff1a;本案例是在F100-C-G2的Version 7.1.064, Release 9510P08版本上进行…

Jenkins通过Pipeline流水线方式编译前端项目

本文记录了本人在前端项目持续集成与自动化部署方面的实践经验&#xff0c;使用 Jenkins 官方 jenkins:lts 镜像为基础&#xff0c;构建支持 Node.js 构建和压缩能力的运行环境&#xff0c;并通过声明式 Pipeline 实现一套多环境&#xff08;SIT/PROD&#xff09;可选的一键部署…

Dockerfile 镜像构建

目录 简介 一、Docker镜像概念与结构 1.1 镜像的分层存储机制 1.2 镜像分层的关键特性 二、Dockerfile语法 2.1 基础构建指令 2.2 环境配置指令 2.3 文件操作指令 2.4 运行时指令 2.5 网络与数据管理 三、实战案例 3.1 构建Nginx Web服务器 3.2 构建Tomcat应用服务…

Docker Desktop 4.42集成的MCP工具包

一、介绍 Docker Desktop 4.42 集成了 MCP&#xff08;Model‑Client‑Plugin&#xff09;Toolkit&#xff0c;无需额外安装扩展即可直接使用。 MCP Toolkit 集成细节 内置于 Docker Desktop&#xff1a;你可以直接打开应用&#xff0c;在设置中启用 MCP 服务器&#xff0c;比…