opengl 深度详解_一步步学OpenGL(23) -《阴影贴图1》

dd462759483ad3e0702858674426d536.png

教程 23

阴影贴图1

f448ce45d985bac57975bfede612f3fc.png

原文: http://ogldev.atspace.co.uk/www/tutorial23/tutorial23.html

CSDN完整版专栏: https://blog.csdn.net/cordova/article/category/9266966


背景

阴影和光是紧密联系的,正如你需要光才能投射出阴影。有许多的技术可以生成阴影,在接下来的两个章节中我们将学习一种基础而简单的技术-阴影贴图。

当涉及到光栅化和阴影的问题时,你可能会问这个像素是否位于阴影中?或者说,从光源到像素的路径是否通过其他物体?如果是,这个像素可能位于阴影中(假定其他的物体不透明),否则,则像素不位于阴影中。从某种程度上讲,这个问题类似于我们在之前的教程中问的问题:如何确定当两个物体重叠时,我们看到的是比较近的那个?如果我们把相机放在光源的位置,那么这两个问题就是一会儿事儿了。我们希望在深度测试中落后的像素是因为像素处于阴影中。只有在在深度测试中获胜的像素才会受到光的照射。这些像素都是直接和光源接触的,其间没有任何东西会遮蔽它们。这就是在阴影贴图背后的原理。

看似深度测试可以帮助我们检测一个像素是否位于阴影中,但是还有一个问题:相机和光源并不总是位于同一个地方。深度测试通常用于解决从相机角度看物体是否可见的问题。那么当光源处于远处的时候,我们如何利用深度测试来进行阴影测试?解决方案是渲染场景两次。首先从光源的角度来看,此时渲染通道的结果并没有存储到颜色缓冲区中,相反,离光源最近的深度值被渲染到应用程序创建的深度缓冲区中(而不是由GLUT自动生成的);其次,从摄像机的角度来看场景,我们创建的深度缓冲区被绑定到片元着色器以便读取。对于每一个像素,我们从这个深度缓冲区中取出相应的深度值,同时我们也计算这个像素到光源的距离。有时候这两个深度值是相等的。说明这个像素与光源最近,因此它的深度值才会被写进深度缓冲区,此时,这个像素就被认为处于光照中会和正常情况一样去计算它的颜色。如果这两个深度值不同,意味着从光源看这个像素时有其他像素遮挡了它,这种情况下我们在颜色计算中要增加阴影因子来模仿阴影效果。看下面这幅图:

aeb8d95e9ac3b6438afb87842da0a80f.png

以上场景由两个对象组成——物体表面和立方体。光源是位于左上角并且指向立方体。在第一次渲染过程中,我们从光源的角度呈现深度缓冲区。看图中A,B,C这3个点。当B被渲染时,它的深度值进入深度缓冲区,因为在B和光源之间没有任何东西,我们默认它是那条线上离光源最近的点。然而当A和C被渲染的时候,它们在深度缓冲区的同一个点上“竞争”。两个点都在同一条来自光源的直线上,所以在透视投影后,光栅器发现这两个点需要去往屏幕上的同一个像素。这就是深度测试,最后C点“赢”了,则C点的深度值被写入了深度缓存中。

在第二个渲染过程中,我们从摄像机的角度渲染表面和立方体。我们在着色器中除了为每个像素做一些计算,我们还计算从光源到像素之间的距离,并和在深度缓冲区中对应的深度值进行比较。当我们光栅化B点时,这两个值应该是差不多相等的(可能由于插值的不同和浮点类型的精度问题会有一些差距),因此我们认为B不在阴影中而和往常一样进行计算。当光栅化A点的时候,我们发现储存的深度值明显比A到光源的距离要小。所以我们认为A在阴影中,并且在A点上应用一些阴影参数,使它比以往暗一些。

简言之,这就是阴影映射算法(我们在第一次渲染通道中渲染的深度缓冲称为“阴影贴图”),我们将分两个阶段学习它。在第一个阶段(本节)我们将学习如何将深度信息渲染到阴影图中,渲染一个由应用程序创建的纹理,被称为 '纹理渲染 ;我们将使用一个简单的纹理映射技术在屏幕上显示阴影贴图,这是一个很好的调试过程,为了得到完整的阴影效果,正确的绘制阴影贴图是至关重要的。在下一节我们将看见如何使用阴影图来计算顶点“是否处于阴影中”。

这一节我们使用的模型是一个简单的可以用来显示阴影贴图的四边形网格。这个四边形是由两个三角形组成的,并设置纹理坐标使它们覆盖整个纹理。当四边形被渲染的时候,纹理坐标被光栅器插值,于是就可以采样整个纹理并将其显示在屏幕上。

源代码详解

(shadow_map_fbo.h:50)

class ShadowMapFBO
{public:ShadowMapFBO();~ShadowMapFBO();bool Init(unsigned int WindowWidth, unsigned int WindowHeight);void BindForWriting();void BindForReading(GLenum TextureUnit);private:GLuint m_fbo;GLuint m_shadowMap;
};

在OpenGL中3d管线输出的结果称为'帧缓冲对象‘(简称FBO)。FBO可以挂载颜色缓冲(在屏幕上显示)、深度缓冲区和一些有其他用处的缓冲区。当glutInitDisplayMode()被调用的时候,它使用一些特定的参数来创建默认的帧缓存,这个帧缓存被窗口系统所管理,不会被OpenGL删除。除了默认的帧缓存,应用程序可以创建自己的FBOs。在应用程序的控制下,这些对象可以被操作以用于不同的技术当中。ShadowMapFBO类为FBO提供一个容易操作的接口,会被FBO用来实现阴影贴图技术。ShadowMapFBO类内部有两个OpenGL句柄,其中'm_fbo'句柄代表真正的FBO,FBO封装了帧缓存所有的状态,一旦这个对象被创建并设置合适的参数,我们就可以简单的通过绑定不同的对象来改变帧缓存。注意只有默认的帧缓存才可以在屏幕上显示。应用程序创建的帧缓存只能用于”离屏渲染“,这个可以说是一个中间的渲染过程(比如我们的阴影贴图缓冲区),稍后可以用于屏幕上的“真实”渲染通道。

就其本身而言,帧缓存只是一个占位符,为了使它变得可用,我们需要把纹理依附于一个或者更多的可用的挂载点,纹理含有帧缓存实际的内存空间。OpenGL定义了下面的一些附着点:

  • COLOR_ATTACHMENTi:附着到这里的纹理将接收来自片元着色器的颜色。‘i’ 后缀意味着可以有多个纹理同时被附着为颜色附着点。在片元着色器中有一个机制可以确保同时渲染多个颜色到缓冲区。
  • DEPTH_ATTACHMENT:附着在上面的纹理将收到深度测试的结果。
  • STENCIL_ATTACHMENT:附着在上面的纹理将充当模板缓冲区。模板缓冲区限制了光栅化的区域,可被用于不同的技术。
  • DEPTH_STENCIL_ATTACHMENT:这仅是一个深度和模板缓冲区的结合,因为它俩经常被一起使用。

对于阴影映射技术,我们只需要一个深度缓冲。成员属性“m_shadowmap“是附加到DEPTH_ATTACHMENT附着点的纹理句柄。ShadowMapFBO也提供了一些方法,主要用在渲染功能上。在开始第二次渲染的时候,我们要在渲染到阴影图和BindForReading()之前调用BindForWriting()。

(shadow_map_fbo.cpp:43)

glGenFramebuffers(1, &m_fbo);

这里我们创建FBO。和纹理与缓冲区这些对象的创建方式一样,我们指定一个GLuints数组的地址和它的大小,这个数组被句柄填充。

(shadow_map_fbo.cpp:46)

glGenTextures(1, &m_shadowMap);
glBindTexture(GL_TEXTURE_2D, m_shadowMap);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, WindowWidth, WindowHeight, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

接下来我们创建纹理来作为阴影图。在一般情况下,这是一个标准的有特定配置的2D纹理,使其用于达到以下目的:

  1. 纹理的内部格式是 GL_DEPTH_COMPONENT 。和之前不同,之前我们通常将纹理的内部格式设置为与颜色有关的类型如(GL_RGB),这里我们将其设置为 GL_DEPTH_COMPONENT,意味着纹理中的每个纹素都存放着一个单精度浮点数用于存放已经标准化后的深度值。
  2. glTexImage2D的最后一个参数是空,意味着我们不提供任何用于初始化buffer的数据,因为我们想让buffer包含每一帧的深度值并且每一帧的深度值都可能会变化。无论我们何时开始一个新的帧,我们都要用glClear()清除buffer。这些是我们在初始化过程中要做的。
  3. 我们告诉OpenGL如果纹理坐标越界,需要将其截断到[0,1]之间。当以相机为视口的投影窗口超过以光源为视口的投影窗口时会发生纹理坐标越界。为了避免不好的现象比如由于wraparound的原因阴影在别的地方重复出现,我们要截断纹理坐标。 (shadow_map_fbo.cpp:54)

glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);

我们已经生成FBO纹理对象,并为阴影贴图配置了纹理对象,现在我们需要把纹理对象附到FBO。我们要做的第一件事就是绑定FBO,之后所有对FBO的操作都会对它产生影响。这个函数的参数是FBO句柄和所需的target。target可以是GL_FRAMEBUFFER,GL_DRAW_FRAMEBUFFER或者GL_READ_FRAMEBUFFER。GL_READ_FRAMEBUFFE在我们想调用glReadPixels(本教程中不会使用)从FBO中读取内容时会用到;当我们想要把场景渲染进入FBO时需要使用GL_DRAW_FRAMEBUFFE;当我们使用GL_FRAMEBUFFER时,FBO的读写状态都会被更新,建议这样初始化FBO;当我们真正开始渲染的时候我们会使用GL_DRAW_FRAMEBUFFER。

(shadow_map_fbo.cpp:55) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_shadowMap, 0);

这里我们把shadow map纹理附着到FBO的深度附着点上。这个函数最后一个参数指明要用的Mipmap层级。Mipmap层是纹理贴图的一个特性,以不同分辨率展现一个纹理。0代表最大的分辨率,随着层级的增加,纹理的分辨率会越来越小。将Mipmap纹理和三线性滤波结合起来能产生更好的结果。这里我们只有一个mipmap层,所以我们使用0。我们让shadow map句柄作为第四个参数。如果这里我们使用0,那么当前的纹理(在上面的例子是深度)将从指定的附着点上脱落。

(shadow_map_fbo.cpp:58)
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);

因为我们没打算渲染到color buffer(只输出深度),我们通过上面的函数来禁止向颜色缓存中写入。默认情况下,颜色缓存会被绑定在GL_COLOR_ATTACHMENT0上,但是我们的FBO中甚至不会包含一个纹理缓冲区,所以,最好明确的告诉OpenGL我们的目的。这个函数可用的参数是GL_NONE和GL_COLOR_ATTACHMENT0到 GL_COLOR_ATTACHMENTm,‘m’是(GL_MAX_COLOR_ATTACHMENTS–1)。这些参数只对FBOs有效。如果用了默认的framebuffer,那么有效的参数是GL_NONE, GL_FRONT_LEFT,GL_FRONT_RIGHT,GL_BACK_LEFT和GL_BACK_RIGHT,这使你可以直接将场景渲染到front buffer或者back buffer(每一个都有左left和right buffer)。我们也将从缓存中的读取操作设置为GL_NONE(注意,我们不打算调用glReadPixel APIs中的任何一个函数)。这主要是为了避免因GPU只支持 opengl3.x而不支持4.x而出现问题。

(shadow_map_fbo.cpp:61)

GLenum Status = glCheckFramebufferStatus(GL_FRAMEBUFFER);if (Status != GL_FRAMEBUFFER_COMPLETE) {printf("FB error, status: 0x%xn", Status);return false;
}

当我们完成FBO的配置后,一定要确认其状态是否为OpenGL定义的“complete”,确保没有错误出现并且framebuffer现在是可用的了。上面就是检验这个的代码。 (shadow_map_fbo.cpp:72)

void ShadowMapFBO::BindForWriting()
{glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo);
}

在渲染过程中我们需要将渲染目标在shadow map和默认的framebuffer之间进行切换。在第二个渲染过程中,我们要绑定shadow map作为输入。这个函数和下一个函数将这个工作封装起来便于调用。上面的函数仅绑定FBO用于写入数据,在第一次渲染之前我们将调用它。

(shadow_map_fbo.cpp:78)

void ShadowMapFBO::BindForReading(GLenum TextureUnit)
{glActiveTexture(TextureUnit);glBindTexture(GL_TEXTURE_2D, m_shadowMap);
}

这个函数在第二次渲染之前被调用以绑定shadow map用于读取数据。注意我们是绑定纹理对象而不是FBO本身。这个函数的参数是纹理单元,并把shadow map绑定到这个纹理单元上。这个纹理单元的索引一定要和着色器同步(因为着色器有一个sampler2D一致变量用来访问这个纹理)。注意glActiveTexture的参数是纹理索引的枚举值(比如GL_TEXTURE0,GL_TEXTURE1等),着色器中的一致变量只需要索引值本身(如0,1等),这可能会导致很多bug出现。

(shadow_map.vs)

#version 330layout (location = 0) in vec3 Position;
layout (location = 1) in vec2 TexCoord;
layout (location = 2) in vec3 Normal;uniform mat4 gWVP;out vec2 TexCoordOut;void main()
{gl_Position = gWVP * vec4(Position, 1.0);TexCoordOut = TexCoord;
}

我们将在两次的渲染中都使用同一着色器程序。顶点着色器在两次渲染过程中都用得到,而片元着色器将只在第二次渲染过程中被使用。因为我们在第一次渲染过程中禁止把数据写入颜色缓存,所以就没用到片元着色器。上面的顶点着色器是十分简单的,它仅仅是通过WVP矩阵将位置坐标变换到裁剪坐标系中,并将纹理坐标传递到片元着色器中。在第一次的渲染过程中,纹理坐标是多余的(因为没有片元着色器)。然而,这没有实际的影响。可以看出,从着色器角度来看,无论这是一个渲染深度的过程还是一个真正的渲染过程都没有什么不同,而真正不同的地方是应用程序在第一次渲染过程传递的是以光源为视口的WVP矩阵,而在第二次渲染过程传递的是以相机为视口的WVP矩阵。在第一次的渲染过程Z buffer将用最靠近光源位置的Z值所填充,在第二次渲染过程中,Z buffer将被最靠近相机位置的Z值所填充。在第二次渲染过程中我们需要使用片元着色器中的纹理坐标,因为我们将从shadow map(此时它是着色器的输入)中进行采样。

(shadow_map.fs)

#version 330in vec2 TexCoordOut;
uniform sampler2D gShadowMap;out vec4 FragColor;void main()
{float Depth = texture(gShadowMap, TexCoordOut).x;Depth = 1.0 - (1.0 - Depth) * 25.0;FragColor = vec4(Depth);
}

这是在渲染过程中用来显示shadow map的片元着色器。2D纹理坐标用来从shadow map中进行采样。Shadow map纹理是以GL_DEPTH_COMPONENT类型为内部格式而创建的,意味着纹理中每一个纹素都是一个单精度的浮点型数据而不是一种颜色。这就是为什么在采样的过程中要使用'.x'。当我们显示深度缓存中的内容时,我们可能遇到的一个情况是渲染的结果不够清楚。所以,在我们从shadow map中采样获得深度值后,为使效果明显,我们放大当前点的距离到远边缘(此处Z为1),然后再用1减去这个放大后值。我们将这个值作为片元的每个颜色通道的值,意味着我们将得到一些灰度的变化(远裁剪面处是白色,近裁剪面处是黑色)。

现在我们如何结合上面的这些代码片段来创建应用程序。

(tutorial23.cpp:106)
virtual void RenderSceneCB()
{m_pGameCamera->OnRender();m_scale += 0.05f;ShadowMapPass();RenderPass();glutSwapBuffers();
}

主渲染程序随着大部分的功能移到其他函数中变得更加简单了。我们先处理全局的东西,比如更新相机的位置和用来旋转对象的类成员。然后我们调用一个ShadowMapPass()函数将深度信息渲染到shadow map纹理中,接着用RenderPass()函数来显示这个纹理。最后调用glutSwapBuffer()来将最终结果显示到屏幕上。 (tutorial23.cpp:117)

virtual void ShadowMapPass()
{m_shadowMapFBO.BindForWriting();glClear(GL_DEPTH_BUFFER_BIT);Pipeline p;p.Scale(0.1f, 0.1f, 0.1f);p.Rotate(0.0f, m_scale, 0.0f);p.WorldPos(0.0f, 0.0f, 5.0f);p.SetCamera(m_spotLight.Position, m_spotLight.Direction, Vector3f(0.0f, 1.0f, 0.0f));p.SetPerspectiveProj(20.0f, WINDOW_WIDTH, WINDOW_HEIGHT, 1.0f, 50.0f);m_pShadowMapTech->SetWVP(p.GetWVPTrans());m_pMesh->Render();glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

在渲染Shadow map之前我们先绑定FBO。从现在起,所有的深度值将被渲染到shadow map中,同时舍弃颜色的写入过程。我们只在渲染开始之前清除深度缓冲区,之后我们为了渲染mesh(例子为一个坦克)初始化了一个pipeline类对象。这里值得注意的一点是相机相关设置是基于聚光灯的位置和方向的。我们先渲染mesh,然后通过绑定FBO为0来切换回默认的framebuffer。

(tutorial23.cpp:135)

virtual void RenderPass()
{glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);m_pShadowMapTech->SetTextureUnit(0);m_shadowMapFBO.BindForReading(GL_TEXTURE0);Pipeline p;p.Scale(5.0f, 5.0f, 5.0f);p.WorldPos(0.0f, 0.0f, 10.0f);p.SetCamera(m_pGameCamera->GetPos(), m_pGameCamera->GetTarget(), m_pGameCamera->GetUp());p.SetPerspectiveProj(30.0f, WINDOW_WIDTH, WINDOW_HEIGHT, 1.0f, 50.0f);m_pShadowMapTech->SetWVP(p.GetWVPTrans());m_pQuad->Render();
}

在第二个渲染过程开始前,我们先清除颜色和深度缓存,这些缓冲区属于默认的帧缓存。我们告诉着色器使用纹理单元0,并绑定阴影贴图用来读取其中的数据。从这里开始处理就都和以前一样了。我们放大四边形,把它直接放在相机的前面并渲染它。在光栅化期间进行采样阴影贴图并将其显示到模型上。

注意:在这个教程的代码中,当网格文件没有指定一个纹理时,我们不再自动加载一个白色的纹理,因为现在可以绑定阴影贴图来代替。如果网格不包含纹理我们就什么都不绑定,而是调用代码让其绑定自己的纹理。

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

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

相关文章

ug后处理如何加密_UG在NX加工中如何添加后处理文件?

在使用UG加工中,往往使用的机床不一样就要特定后处理文件,那么如何在UG中添加之前制定好的后处理文件呢?下面以UG8.5为例来说明。1、首先确认UG后处理文件是否完整。完整的后处理文件包括后缀为.def、.pui和.tcl的三个文件(注&…

华为mstp多生成树配置_网络工程师(30):多实例生成树如何计算

多实例生成树MSTP包括域间的外部生成树CST和域内的内部生成树IST,我们通称为CIST。我们先讨论CST的计算。在CST中,一个MST域看作是一台"交换机",那么在进行CST计算时,这台"交换机"的桥ID是多少呢?…

url中能出现的字符_python爬虫,解决大众点评字符库反爬机制的经验

刚开始写文章还希望大家可以喜欢,对于爬虫只是个人整理出的方法,爬虫大牛请嘴下留情。“”仅限学术交流,如有冒犯请联系作者删除“”话不多说,想分析天津地区餐饮行业的大致情况,要爬出(商铺名称&#xff0…

上课点名app_【APP种草】网瘾少年的自我救赎之最强锁机软件

相信在这个魔幻的2020,大家都经历了很多个不寻常吧。作为学生党,算是圆梦了在家学习的愿望,可当这一切都变成现实的时候,也还是没逃过点名、没逃过网课,这不,连期末考也又双叕叕地来了。作为一名需要在家完…

qrcode生产带logo_比亚迪换新标?新Logo的含义你了解吗?

对于许多制造业品牌来说,由于时代发展的速度太快,科技的力量进步太快,即便是规模庞大的老牌企业,也需要不断改变自己,以此来适应社会的改变求得生存。这就意味着,无论是什么品牌,都需要定期改变…

超前进位加法器实验报告_干货 | 加法器与反相加法器原理解析

什么是加法器加法器是为了实现加法的,即是产生数的和的装置。加数和被加数为输入,和数与进位为输出的装置为半加器。若加数、被加数与低位的进位数为输入,而和数与进位为输出则为全加器。常用作计算机算术逻辑部件,执行逻辑操作、…

php 支付宝小程序授权登陆验签_星巴克“啡快”登陆支付宝小程序,让你“飞快”取到咖啡...

当代年轻人的生活方式是怎样的?靠地铁通勤,靠咖啡续命早上睁不开眼,咖啡来一杯中午昏昏欲睡,咖啡来一杯晚上熬夜加班,咖啡来一杯喝完这杯,还有一杯“宁可食无肉,不可早无星”是当代年轻人的座右…

python导入同一文件夹下的类_python自定义模块

模块的引入方式:1.import 模块名:导入模块中的所有内容(引入多个用逗号分隔)import random,time2.from 模块名 import 函数名1,函数名2...导入部分模块(导入部分的话直接使用)3.from 模块名 imp…

上河南星海科技_揭秘丨赣江新区网红打卡点,为你按下科技快进键!

人类对科学和未来永无止境的求知欲,是人类社会发展的根本动力之一。整合历史长河中积累的科学文明,探索和体验未来的黑科技,在赣江新区,一座国际创新科技馆在全城翘首中揭开了神秘面纱,一举跃升为赣江新区的网红打卡点…

模糊匹配查询_必须掌握的6个查询函数应用技巧,办公必备,收藏备用!

在Excel中,有一类函数被称为查找和引用函数,今天,小编给大家分享6个查询函数(Choose、Lookup、Hlookup、Vlookup、Match、Index)的应用技巧,可以收藏备用哦!一、Choose。功能:根据序…

1万并发服务器配置_小程序后端服务器搭建:云服务器配置(1)

起因最近在搞小程序,有一个留言与图片上传并展示的功能,用小程序自带云服务器也可以实现,但如果与别的端进行多端互动就需要一个服务器来做为后端,进行图片与留言的上传,并把留言内容和上传后的图片地址保存到sql数据库…

ext 如何判断是否是整数_Excel表格技巧—如何用ISNUMBER判断是否是数值

在EXCEL的单元格中,有些单元格为填写的不是数值,在某些情况下,会影响计算结果,例如,以下的表格中,红框内的单元格一个是输入了一个空格,另一个“—”符号,后面平均值的计算未将该单元…

ensp安装对电脑配置要求高吗_直线导轨有哪些安装方法?为什么直线导轨安装精度要求高?...

要点:1、为什么直线导轨安装精度要求高;2、直线导轨的安装流程;3、直线导轨不同安装方法介绍。点击链接加入群聊【solidworks机械设计学习】:正在跳转​jq.qq.comhttps://www.zhihu.com/video/1197242052088516608

mysql查看版本号_十分钟了解MySQL事务机制

读书百遍其义自现。MySQL数据库在我们平时工作学习中的使用频率是相当之高,彻底掌握MySQL的事务机制对我们平时工作会有非常大的帮助,仔细回忆一下,你是否对MySQL事务相关的知识是否完全掌握?是否感觉有的地方有些模糊&#xff1f…

mysql 字符串类型 分区_MySQL分区类型

博文大纲:1、RANGE分区2、LIST分区3、HASH分区4、key分区5、MySQL分表和分区的区别6、附加:如何实现将分区放在不同的目录下进行存储MySQL分区类型如下:RANFGE分区LIST分区HASH分区key分区上面的四种分区的条件必须是整形,如果不是…

mysql免安装如何改密码_mysql免安装版配置与修改密码的教程

第一步:配置环境变量(我的解压路径:G:\mysql\mysql-5.7.21-winx64 )MYSQL_HOME你解压的路径PATH ;%MYSQL_HOME %\bin;PATH变量是在原来的基础上多添加的,不要把其它的设置给删掉了第二步在解压的目录下添加my.ini 文件(如果已经有了这个文件&#xff0c…

拉普拉斯时域卷积定理_如何证明频域卷积定理

展开全部设抄IF表示傅立叶逆变换,则因此有袭故频域卷积定2113理5261得证。4102扩展资料频域卷积定理频域卷积定理表明两信号1653在时域的乘积对应于这两个信号傅立叶变换的卷积除以2π。卷积定理揭示了时间域与频率域的对应关系。这一定理对Laplace变换、Z变换、Mel…

suse查看mysql内存使用情况_MySQL 慢查询日志(Slow Query Log)

4、格式化慢查询日志结构化慢查询日志就是把慢查询日志中的重要信息按照便于阅读以及按照特定的排序方式来提取SQL。这种方式有点类似于Oracle中有个tkprof来格式化oracle的trace文件。对于前面的慢查询日志我们使用MySQLdumpslow来提取如下:SUSE11b:~ # mysqldumps…

mysql 分析服务_MySQL分析服务器状态_MySQL

概述文章简单介绍了通过一些查询命令分析当前服务器的状态。目录概述获取服务器整体的性能状态SQL操作计数总结步骤获取服务器整体的性能状态首先对一个数据库服务器进行性能优化需要先知道服务器当前主要的性能问题出现在哪里,在这点sql server也是类似&#xff0c…

python 接口测试 如何写配置文件_python接口自动化测试 - configparser配置文件解析器详细使用...

configparser简介ConfigParser模块已在Python 3中重命名为configparser该模块定义了ConfigParser类。 ConfigParser类实现一种基本的配置文件解析器语言,该语言提供的结构类似于 .ini 文件中的结构ini文件相关知识键值对可用 或者 : 进行分隔section 的名字是区分大…