Python+OpenGL绘制3D模型(六)材质文件载入和贴图映射

系列文章

一、逆向工程
Sketchup 逆向工程(一)破解.skp文件数据结构
Sketchup 逆向工程(二)分析三维模型数据结构
Sketchup 逆向工程(三)软件逆向工程从何处入手
Sketchup 逆向工程(四)破解的乐趣 钩子 外挂 代码注入

二、OpenGL渲染模型
Python+OpenGL绘制3D模型(一)Python 和 PyQt环境搭建
Python+OpenGL绘制3D模型(二)程序框架PyQt5
Python+OpenGL绘制3D模型(三)程序框架PyQt6
Python+OpenGL绘制3D模型(四)绘制线段
Python+OpenGL绘制3D模型(五)绘制三角型
Python+OpenGL绘制3D模型(六)材质文件载入和贴图映射
Python+OpenGL绘制3D模型(七)制作3dsmax导出插件
Python+OpenGL绘制3D模型(八)绘制插件导出的插件
Python+OpenGL绘制3D模型(九)完善插件功能: 矩阵,材质,法线
Python+OpenGL 杂谈(一)

三、成果
疫情期间关在家里实在没事干,破解了Sketchup,成功做出可以读取并显示.skp文件的程序SuViewer

前言

Sketchup作为目前设计院最为流行的设计软件(非工程制图软件),深受设计师的喜爱,软件小巧,而功能强大,有不少为之开发的插件应运而生,不过呢,关于底层数据结构和工作原理相关的文章少之又少,本文意在填补一下这方面的空缺,通过逆向软件分析,展示软件内部奥秘。本文用到的工具:IDA Pro,Immunity Debugger,Visual Studio (逆向工程三件套)数据结构属于知识产权的核心机密:


Python+OpenGL绘制3D模型(六)材质文件载入和贴图映射

运行效果:
在这里插入图片描述

文章目录

  • 系列文章
  • 前言
  • Python+OpenGL绘制3D模型(六)材质文件载入和贴图映射
    • 一、从文件读取贴图
    • 二、glBindTexture
    • 三、指定贴图坐标
    • 四、运行图效果
    • 五、2个问题和原因
    • 六、源代码
      • 1、Draw1.py
      • 2、tOpenGLqt5.py
  • 系列文章预告

一、从文件读取贴图

记得以前用c++写的时候,要编译链接图像库,用于对应图片格式的加载,每个用到的格式都要单独搞一遍,在网上找开源的图片库,下载,编译,测试,一套下来搞的人很累,现在,因为有Qt的加持,载入贴图变得非常简单,全部交给Qt来做,只需要几行代码

def load_texture_from_file( filepath ):with open(filepath, 'rb') as hf:data = hf.read()image = QImage()valid = image.loadFromData(data)if not valid:return Falsegl_tex_obj = QOpenGLTexture(image.mirrored())return gl_tex_obj

图片载入到Qt后,还需要调用OpenGL的库加载贴图数据,另外Qt的图片坐标Y轴是向下增加的,符合显示屏幕坐标的习惯,而OpenGL中的Y轴坐标是正常向上的,所以Y轴需要mirror处理一下

is_built = False
gl_tex = Nonedef draw(gl):global is_built, gl_texif not is_built:gl_tex = load_texture_from_file("c:/temp/cg.jpg")is_built = True

为了代码保持简洁,简化接口,不要把简单的事情复杂化:
1、载入贴图后,对象保存到全局对象中,
2、载入模型的初始工作也内嵌到draw函数中执行,这种思维在项目越做越大也仍然实用
3、贴图路径使用了硬编码方式的绝对路径,在没有形成一个模型框架的时候,暂且用这种方式对测试减少不少工作量

演示用到的贴图文件下载:
在这里插入图片描述

二、glBindTexture

在绘制模型前,设置一下OpenGL的状态机,调用glBindTexture指定当前纹理单元的数据,然后调用glEnable(GL_TEXTURE)激活纹理单元,因为有贴图作为像素的输入颜色,所以颜色设为纯白

    gl.glDisable(gl.GL_TEXTURE_2D)gl.glColor3f(0.9, 0.83, 0.6)# 绘制上下2个面draw_single_face(p1, p2, p3, p4, uv1,  uv2,  uv3,  uv4, gl)draw_single_face(p5, p6, p7, p8, uv1,  uv2,  uv3,  uv4,  gl)gl_tex.bind()gl.glEnable(gl.GL_TEXTURE_2D)gl.glColor3f(1, 1, 1)# 绘制其他4个面,前,后,左,有draw_single_face(p1, p2, p6, p5, uv1,  uv2,  uv3,  uv4, gl)draw_single_face(p3, p4, p8, p7, uv1,  uv2,  uv3,  uv4, gl)draw_single_face(p2, p3, p7, p6, uv1,  uv2,  uv3,  uv4, gl)draw_single_face(p4, p1, p5, p8, uv1,  uv2,  uv3,  uv4, gl)

在本例中,前后左右的面映射了贴图,上下2个面仍然用了原来的模型颜色(淡黄色)

三、指定贴图坐标

在调用glVertex3f之前,需要先指定顶点的贴图坐标属性,调用glTexCoord2f

    gl.glBegin(gl.GL_TRIANGLES)# 第一个顶点gl.glTexCoord2f( ... )gl.glVertex3f( ... )# 第二个顶点gl.glTexCoord2f( ... )gl.glVertex3f( ... )# 第三个顶点gl.glTexCoord2f( ... )gl.glVertex3f( ... )# 完成gl.glEnd()

四、运行图效果

在这里插入图片描述

五、2个问题和原因

第一、模型的位置有点高:

这是应为camera坐标系的中心为(0,0,0), 而模型高度是从 0.0 到 2.0,要调整一下中心坐标,可以通过设置概念上的world matrix沿Z轴往下移动1.0个单位,模型就居中了,目前程序框架里控制视角的平移,也可以通过这个方法来解决,不过我还是打算在之后引入Camera对象的计算,计算的逻辑思维更清晰,不容易出错

    # Cameraself.gl.glMatrixMode(self.gl.GL_MODELVIEW)self.gl.glLoadIdentity()self.gl.glTranslatef(0.0,0.0,-self.zoom)self.gl.glRotatef(self.rotX-90,1.0,0.0,0.0)self.gl.glRotatef(self.rotZ,0.0,0.0,1.0)# Worldself.gl.glTranslatef(0.0,0.0,-1.0)  # 在这里加上对world matrix的改变

这里的矩阵叠加,是按照相反的顺序乘积的,比较容易搞错,OpenGL中有个机制 PushMatrix PopMatrix,也就是说后面加入的矩阵,可以通过PopMatrix来恢复到之前的矩阵乘积的状态,越靠后面加进来的矩阵,代表子物体的矩阵,在运算中最先乘这个矩阵

第二、当模型放大的时候,近的地方会被切掉

调整下几行代码,

    # Projectionself.gl.glMatrixMode(self.gl.GL_PROJECTION)pm = QMatrix4x4()aspectRatio = w/hfov = 45 / aspectRatio if w < h else 45pm.perspective(fov,  w/h,  2,  5000)self.gl.glLoadMatrixf(pm.data())

这里是设置透视投影矩阵的代码,pm.perspective(fov, w/h, 2, 5000),这个函数调用的最后2个参数,分别代表了近裁剪平面(z-buff=0.0),和远裁剪平面(z-buff=1.0),这2个值明显不太匹配当前场景的大小,每次应该根据当前场景大小来适当选择取值范围

    pm.perspective(fov,  w/h,  0.1,  100)

改成 0.1 到 100 的范围,就能够比较适配当前的测试模型
在这里插入图片描述
到此我们已经能够绘制一个完整的模型,不过模型数据来源还没解决,不能显示复杂的模型,下节我们要讲一个模型数据来源的通用方法,通过编写一个3dsmax插件导出模型,因为3dsmax也支持python,所以下节我们用很少的python代码来完成一个复杂的模型导出插件

六、源代码

1、Draw1.py

from PyQt5.QtGui import QVector3D, QVector2D, QImage,  QOpenGLTexture################################
#                   FILE DESCRIPTION
#  文件描述:load_texture_and_bind()
#  对应文章:Python+OpenGL绘制3D模型(六) 载入贴图及映射到模型
#  作者:李航 Lihang
#
################################is_built = False
gl_tex = Nonedef draw(gl):global is_built, gl_texif not is_built:gl_tex = load_texture_from_file("c:/temp/cg.jpg")is_built = True# 设置z-buff偏移gl.glEnable(gl.GL_POLYGON_OFFSET_FILL)gl.glPolygonOffset(1, 1)# 绘制填充面draw_box_faces(gl_tex, gl)# 关闭z-buff偏移gl.glDisable(gl.GL_POLYGON_OFFSET_FILL)# 绘制线框gl.glColor3f(0.0, 0.0, 0.0)draw_box_lines(gl)def load_texture_from_file( filepath ):with open(filepath, 'rb') as hf:data = hf.read()image = QImage()valid = image.loadFromData(data)if not valid:return Falsegl_tex_obj = QOpenGLTexture(image.mirrored())return gl_tex_obj############
# draw_box_faces
#   画面 - 中间的填充部分
############
def draw_box_faces(gl_tex, gl):p1 = QVector3D(-1, -1, 0 )p2 = QVector3D(+1, -1, 0 )p3 = QVector3D(+1, +1, 0 )p4 = QVector3D(-1, +1, 0 )p5 = QVector3D(-1, -1, 2 )p6 = QVector3D(+1, -1, 2 )p7 = QVector3D(+1, +1, 2 )p8 = QVector3D(-1, +1, 2 )uv1 = QVector2D(0, 0)uv2 = QVector2D(1, 0)uv3 = QVector2D(1, 1)uv4 = QVector2D(0, 1)gl.glDisable(gl.GL_TEXTURE_2D)gl.glColor3f(0.9, 0.83, 0.6)draw_single_face(p1, p2, p3, p4, uv1,  uv2,  uv3,  uv4, gl)draw_single_face(p5, p6, p7, p8, uv1,  uv2,  uv3,  uv4,  gl)gl_tex.bind()gl.glEnable(gl.GL_TEXTURE_2D)gl.glColor3f(1, 1, 1)draw_single_face(p1, p2, p6, p5, uv1,  uv2,  uv3,  uv4, gl)draw_single_face(p3, p4, p8, p7, uv1,  uv2,  uv3,  uv4, gl)draw_single_face(p2, p3, p7, p6, uv1,  uv2,  uv3,  uv4, gl)draw_single_face(p4, p1, p5, p8, uv1,  uv2,  uv3,  uv4, gl)def draw_single_face(p1, p2, p3, p4, uv1,  uv2,  uv3,  uv4, gl):gl.glBegin(gl.GL_TRIANGLES)gl.glTexCoord2f(uv1.x(), uv1.y())gl.glVertex3f(p1.x(),  p1.y(), p1.z())gl.glTexCoord2f(uv2.x(), uv2.y())gl.glVertex3f(p2.x(),  p2.y(), p2.z())gl.glTexCoord2f(uv3.x(), uv3.y())gl.glVertex3f(p3.x(),  p3.y(), p3.z())gl.glEnd()gl.glBegin(gl.GL_TRIANGLES)gl.glTexCoord2f(uv3.x(), uv3.y())gl.glVertex3f(p3.x(),  p3.y(), p3.z())gl.glTexCoord2f(uv4.x(), uv4.y())gl.glVertex3f(p4.x(),  p4.y(), p4.z())gl.glTexCoord2f(uv1.x(), uv1.y())gl.glVertex3f(p1.x(),  p1.y(), p1.z())gl.glEnd()############
# draw_box_lines
#   画面 - 外侧的线
############
def draw_box_lines(gl):p1 = QVector3D(-1, -1, 0 )p2 = QVector3D(+1, -1, 0 )p3 = QVector3D(+1, +1, 0 )p4 = QVector3D(-1, +1, 0 )p5 = QVector3D(-1, -1, 2 )p6 = QVector3D(+1, -1, 2 )p7 = QVector3D(+1, +1, 2 )p8 = QVector3D(-1, +1, 2 )# 一个立方体有12条边draw_single_line( p1, p2, gl )draw_single_line( p2, p3, gl )draw_single_line( p3, p4, gl )draw_single_line( p4, p1, gl )draw_single_line( p5, p6, gl )draw_single_line( p6, p7, gl )draw_single_line( p7, p8, gl )draw_single_line( p8, p5, gl )draw_single_line( p1, p5, gl )draw_single_line( p2, p6, gl )draw_single_line( p3, p7, gl )draw_single_line( p4, p8, gl )def draw_single_line(p1, p2, gl):gl.glBegin(gl.GL_LINES)gl.glVertex3d(p1.x(),  p1.y(), p1.z())gl.glVertex3d(p2.x(),  p2.y(), p2.z())gl.glEnd()

2、tOpenGLqt5.py

import sys
from PyQt5.QtCore import (QPoint)
from PyQt5.QtGui import (QMatrix4x4, QVector3D, QOpenGLVersionProfile)
from PyQt5.QtWidgets import QApplication, QOpenGLWidgetfrom Draw1 import draw############
# GLWidget
# OpenGL 窗口通用程序框架
#   1、创建OpenGL环境
#   2、设置矩阵
#   3、控制窗口视角
#   4、调用 draw 绘图主函数
############
class GLWidget(QOpenGLWidget):def __init__(self, parent):super(GLWidget, self).__init__( parent)self.dragPressPos = QPoint()self.rotX=45self.rotZ=0self.ps_button = 0self.ps_rotX = 0self.ps_rotZ = 0self.zoom=10############# 创建OpenGL环境# Qt6 和 Qt5的主要区别在这里############def initializeGL(self):version_profile = QOpenGLVersionProfile()version_profile.setVersion(2, 0)self.gl = self.context().versionFunctions(version_profile)self.gl.initializeOpenGLFunctions()############# paintEvent############def paintEvent(self,  event):# Step 0self.makeCurrent()# Step 1self.gl.glClearColor(0.85, 0.85, 0.85, 1.0)self.gl.glClear(self.gl.GL_COLOR_BUFFER_BIT | self.gl.GL_DEPTH_BUFFER_BIT)self.gl.glEnable(self.gl.GL_DEPTH_TEST)# Step 2self.SetupMatrix()# Step 3draw(self.gl)#self.drawTarget(self.gl)############# 绘图# 这里是个绘图的简单测试代码############def drawTarget(self, gl):p = QVector3D(0, 0, 0)gl.glColor3f(1.0, 0.0, 0.0);gl.glBegin(gl.GL_LINES)gl.glVertex3d(p.x()-1,  p.y(),  p.z()  )gl.glVertex3d(p.x()+1,  p.y(),  p.z() )gl.glEnd()gl.glColor3f(0.0, 1.0, 0.0);gl.glBegin(gl.GL_LINES)gl.glVertex3d(p.x(),  p.y()-1,  p.z()  )gl.glVertex3d(p.x(),  p.y()+1,  p.z() )gl.glEnd()gl.glColor3f(0.0, 0.0, 1.0);gl.glBegin(gl.GL_LINES)gl.glVertex3d(p.x(),  p.y(),  p.z()  )gl.glVertex3d(p.x(),  p.y(),  p.z() +4 )gl.glEnd()############# 设置矩阵# 透视矩阵和Camera矩阵############def SetupMatrix(self):# ViewPortw = self.width()h = self.height()self.gl.glViewport(0, 0, w, h)  # Projectionself.gl.glMatrixMode(self.gl.GL_PROJECTION)pm = QMatrix4x4()aspectRatio = w/hfov = 45 / aspectRatio if w < h else 45pm.perspective(fov,  w/h,  0.1,  100)self.gl.glLoadMatrixf(pm.data())# Cameraself.gl.glMatrixMode(self.gl.GL_MODELVIEW)self.gl.glLoadIdentity()self.gl.glTranslatef(0.0,0.0,-self.zoom)self.gl.glRotatef(self.rotX-90,1.0,0.0,0.0)self.gl.glRotatef(self.rotZ,0.0,0.0,1.0)# Worldself.gl.glTranslatef(0.0,0.0,-1)  # 在这里加上对world matrix的改变############# 视角控制# 1、左键旋转# 2、中间缩放# 3、平移 **TODO**############def mousePressEvent(self,event):self.dragPressPos = event.pos()self.ps_button = event.button()self.ps_rotX = self.rotXself.ps_rotZ = self.rotZdef mouseMoveEvent(self, event):diff = event.pos() - self.dragPressPosif self.ps_button == 1:self.rotX = self.ps_rotX + diff.y()*0.5if self.rotX > 90:self.rotX = 90if self.rotX < -90:self.rotX = -90;            # rotZself.rotZ = self.ps_rotZ + diff.x()*0.5self.repaint()def wheelEvent(self, event):delta = event.angleDelta().y()if delta < 0 :self.zoom += self.zoom * 0.2else:self.zoom -= self.zoom * 0.2self.repaint()############
# App
# 创建主窗口应用程序
# 并且进入消息循环
############
if __name__ == '__main__':app = QApplication(sys.argv)widget = GLWidget(None)widget.resize(640, 480)widget.show()sys.exit(app.exec())

系列文章预告

目标是一个完善的Viewer,能够显示Sketchup的.skp文件中的3D模型
在这里插入图片描述

Corona渲染器照片级渲染效果
在这里插入图片描述

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

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

相关文章

WSL使用VsCode运行cpp文件

文章目录 缘起主要步骤参考 缘起 今天在阅读《C20设计模式-可复用的面向对象设计方法&#xff08;原书第2版&#xff09;》的时候&#xff0c;遇到代码想要运行一下&#xff0c;于是决定使用wsl下的vscode配置cpp的环境。 主要步骤 1.安装gcc和g编译器 打开命令行输入wsl&am…

推荐系统中 排序策略 CTR 预估加权平均法

CTR&#xff08;Click-Through Rate&#xff09;预估加权平均法是一种用于估计广告点击率的方法&#xff0c;其中对不同的CTR预估模型赋予不同的权重&#xff0c;通过加权平均来得到整体的CTR预估。这样的方法可以充分利用多个CTR预估模型的优势&#xff0c;提高整体的预估准确…

docker应用部署(部署MySql,部署Tomcat,部署Nginx,部署Redis)

Docker 应用部署 一、部署MySQL 搜索mysql镜像 docker search mysql拉取mysql镜像 docker pull mysql:5.6创建容器&#xff0c;设置端口映射、目录映射 # 在/root目录下创建mysql目录用于存储mysql数据信息 mkdir ~/mysql cd ~/mysqldocker run -id \ -p 3307:3306 \ --na…

TCP服务器的编写(下)

我们现在开始对我们的客户端开始封装 我们的客户端&#xff0c;创建完套接字&#xff0c;需不需要bind呢&#xff1f;&#xff1f; 当然是不需要的&#xff0c;你本身是一个客户端&#xff0c;其他人写的应用也可能是客户端&#xff0c;如果我们bind&#xff0c;一定意味着我们…

CCNP课程实验-05-Comprehensive_Experiment

目录 实验条件网络拓朴配置实现基础配置实现IGP需求&#xff1a;1. 根据拓扑所示&#xff0c;配置OSPF和EIGRP2. 在R3上增加一个网段&#xff1a;33.33.33.0/24 (用Loopback 1模拟) 宣告进EIGRP&#xff0c;并在R3上将EIGRP重分布进OSPF。要求重分布进OSPF后的路由Tag值设置为6…

算法基础之滑雪

滑雪 核心思想&#xff1a;记忆化搜索 状态表示&#xff1a; f[i][j] 表示所有从(i,j) 开始滑的路径的最大值 状态计算&#xff1a; 分成四个方向 f[i][j] max(f[i][j] , f[i][j1] 1) 且h[a][b] (下一个点) 必须严格小于 h[i][j] 才能滑过去 #include<iostream>#…

电压,电流,温度采样检测原理

电流采集电路&#xff1a; 电流采样原理&#xff1a; 电压采样电路&#xff1a; 温度检测&#xff1a;通过热敏电阻实现 以上资料来源于&#xff1a;正点原子&#xff0c;仅做学习笔记使用

模版匹配历劫之路1-匹配点太多如何解决

1测试图片 2初步推测是否是提取的点太多而导致匹配时间很长 2.1通过canny的算法来提取检测点 import numpy as np import cv2 import time import matplotlib.pyplot as pltclass GeoMatch:def __init__(self):self.noOfCordinates0 # 坐标数组中元素的个数self.cordinates…

思维链COT原理探究

要进行因果分析&#xff0c;需要把思维链中的不同元素拆解开来&#xff0c;然后通过控制变量实验&#xff0c;来研究不同元素对COT效果的影响。以下两篇论文的核心差异就在于: COT的变量拆解&#xff0c;以及控制变量的实验方式。 结合两篇论文的实验结论&#xff0c;可能导致…

MIT线性代数笔记-第34讲-左右逆,伪逆

目录 34.左右逆&#xff0c;伪逆左右逆伪逆 打赏 34.左右逆&#xff0c;伪逆 左右逆 之前讲到的逆都是针对可逆方阵而言的&#xff0c;对于长方矩阵&#xff0c;实际上也有广义的逆&#xff0c;那就是左逆和右逆 左逆 当矩阵列满秩&#xff0c;即 r n r n rn时&#xff0c;…

老子的《道德经》透露,不努力反而更成功

人类生而自由&#xff0c;但到处都是枷锁。 永远不要怀疑经过慎思且足够投入的一小群人能否改变这个世界。事实上&#xff0c;只有他们才办得到。 优美灵魂的两个发展方向&#xff1a;崇拜道德的天才&#xff0c;对别人实行道德的判断。 一、道 《道德经》开始的名字是《老子…

关键字:try-catch关键字

在 Java 中&#xff0c;try-catch关键字用于异常处理。它们允许编写代码来捕获和处理异常&#xff0c;以确保程序能够在出现问题时合理地处理它们而不会崩溃。 以下是try-catch关键字的基本语法&#xff1a; 在try块中编写可能会抛出异常的代码。如果在try块中的任何代码抛出…

JavaScript setTimeout和setInterval的用法与区别详解

目录 I. 总述 II. setTimeout()函数 III. setInterval()函数 IV. 新年倒计时案例 Javascript的setTimeOut和setInterval函数应用非常广泛&#xff0c;它们都用来处理延时和定时任务&#xff0c;下面这篇文章主要给大家介绍了关于JavaScript setTimeout和setInterval的用法与…

HTML5和JS实现新年礼花效果

HTML5和JS实现新年礼花效果 2023兔年再见&#xff0c;2024龙年来临了&#xff01; 祝愿读者朋友们在2024年里&#xff0c;身体健康&#xff0c;心灵愉悦&#xff0c;梦想成真。 下面是用HTML5和JS实现新年礼花效果&#xff1a; 源码如下&#xff1a; <!DOCTYPE html>…

MySQL数据库学习一

1 什么是数据库的事务&#xff1f; 1.1 事务的典型场景 在项目里面&#xff0c;什么地方会开启事务&#xff0c;或者配置了事务&#xff1f;无论是在方法上加注解&#xff0c;还 是配置切面。 <tx:advice id"txAdvice" transaction-manager"transactionMa…

个人简历范本(精选5篇)

HR浏览一份简历也就25秒左右&#xff0c;如果你连「好简历」都没有&#xff0c;怎么能找到好工作呢&#xff1f; 如果你不懂得如何在简历上展示自己&#xff0c;或者觉得怎么改简历都不出彩&#xff0c;那请你一定仔细读完。 个人求职简历第 1 篇 男 22 本科 AI简历 市场营…

007、控制流

先看下本篇学习内容&#xff1a; 通过条件来执行 或 重复执行某些代码 是大部分编程语言的基础组成部分。在Rust中用来控制程序执行流的结构主要就是 if表达式 与 循环表达式。 1. if表达式 if表达式允许我们根据条件执行不同的代码分支。我们提供一个条件&#xff0c;并且做出…

【NTN 卫星通信】Oneweb星座以及Oneweb与Starlink比较

1 什么是OneWeb OneWeb于2012年以WorldVu的名义成立&#xff0c;于2020年开始构建其星座。然而&#xff0c;对于这家英国公司来说&#xff0c;这是一个艰难的旅程&#xff0c;OneWeb于2020年3月宣布破产&#xff0c;并认为covid-19大流行是一个主要因素。OneWeb星座当时仅完成…

Redis的缓存过期淘汰策略

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱吃芝士的土豆倪&#xff0c;24届校招生Java选手&#xff0c;很高兴认识大家&#x1f4d5;系列专栏&#xff1a;Spring源码、JUC源码、Kafka原理、分布式技术原理、数据库技术&#x1f525;如果感觉博主的文章还不错的…

RocketMQ(Linux版本5.1.4)

1、停止之前的运行服务 [roottssvr1-c1 rocketmq-all-4.7.0-bin-release]# sh bin/mqshutdown namesrv No mqnamesrv running. [roottssvr1-c1 rocketmq-all-4.7.0-bin-release]# [roottssvr1-c1 rocketmq-all-4.7.0-bin-release]# [roottssvr1-c1 rocketmq-all-4.7.0-bin-r…