当前位置: 首页 > news >正文

第十五章 opengl之高级OpenGL(模板测试)

OpenGL

  • 模板测试
  • 模板函数
  • 物体轮廓

模板测试

当片段着色器处理完一个片段后,模板测试就会开始执行。类似于深度测试,模板测试也可能会丢弃片段。被保留的片段会进入深度测试,可能会丢弃更多的片段。
模板测试是根据模板缓冲来进行的。一个模板缓冲中,通常每个模板值是8位。所以每个像素/片段一共能有256种不同的模板值。可以将模板值设置为想要的值,当某一个片段有某一个模板值的时候,就可以选择丢弃或者保留这个片段。
注意:每个窗口库都需要配置一个模板缓冲。GLFW自动做了,所以不需要告诉GLFW创建一个模板缓冲,但是其他的窗口库不会默认创建一个模板库,需要查看库文档。
举例如下:
在这里插入图片描述
模板缓冲首先会被清除为0,之后在模板缓冲中使用1填充了一个空心矩形。场景中的片段将会只在片段的模板值为1的时候会被渲染(其它的都被丢弃了)。

模板缓冲操作允许我们在渲染片段时将模板缓冲设定为一个特定的值。通过在渲染时修改模板缓冲的内容,我们写入了模板缓冲。在同一个(或者接下来的)渲染迭代中,我们可以读取这些值,来决定丢弃还是保留某个片段。使用模板缓冲的时候你可以尽情发挥,但大体的步骤如下:
1.启用模板缓冲的写入。
2.渲染物体,更新模板缓冲的内容。
3.禁用模板缓冲的写入。
4.渲染(其它)物体,这次根据模板缓冲的内容丢弃特定的片段。
所以,通过使用模板缓冲,我们可以根据场景中已绘制的其它物体的片段,来决定是否丢弃特定的片段。

你可以启用GL_STENCIL_TEST来启用模板测试。在这一行代码之后,所有的渲染调用都会以某种方式影响着模板缓冲:

glEnable(GL_STENCIL_TEST);

和颜色和深度缓冲一样,你也需要在每次迭代之前清除模板缓冲。

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

类似深度测试的glDepthMask函数一样,模板缓冲也有一个类似的函数。glStencilMask允许我们设置一个位掩码(Bitmask),它会与将要写入缓冲的模板值进行与(AND)运算。默认情况下设置的位掩码所有位都为1,不影响输出,**但如果我们将它设置为0x00,写入缓冲的所有模板值最后都会变成0.**这与深度测试中的glDepthMask(GL_FALSE)是等价的。

glStencilMask(0xFF); // 每一位写入模板缓冲时都保持原样
glStencilMask(0x00); // 每一位在写入模板缓冲时都会变成0(禁用写入)

模板函数

和深度测试类似,对模板缓冲应该 通过还是失败,以及应该如何影响模板缓冲,也是有一定控制的。一个有两个函数能够用来配置模板测试:
glStencilFunc和glStencilOp

glStencilFunc(GLenum func, GLint ref, GLuint mask)一共包含三个参数:

func:设置模板测试函数(Stencil Test Function)。这个测试函数将会应用到已储存的模板值上和glStencilFunc函数的ref值上。可用的选项有:GL_NEVER、GL_LESS、GL_LEQUAL、GL_GREATER、GL_GEQUAL、GL_EQUAL、GL_NOTEQUAL和GL_ALWAYS。它们的语义和深度缓冲的函数类似。

ref:设置了模板测试的参考值(Reference Value)。模板缓冲的内容将会与这个值进行比较。

mask:设置一个掩码,它将会与参考值(ref)和储存的模板值在测试比较它们之前进行与(AND)运算。初始情况下所有位都为1。

举例如下:

glStencilFunc(GL_EQUAL, 1, 0xFF)

解释:只要一个片段的模板值等于(GL_EQUAL)参考值1,片段将会通过测试并被绘制,否则会被丢弃。

但是glStencilFunc仅仅描述了OpenGL应该对模板缓冲内容做什么,而不是我们应该如何更新缓冲。这就需要glStencilOp这个函数了。
glStencilOp(GLenum sfail, GLenum dpfail, GLenum dppass)一共包含三个选项,我们能够设定每个选项应该采取的行为:

sfail:模板测试失败时采取的行为。
dpfail:模板测试通过,但深度测试失败时采取的行为。
dppass:模板测试和深度测试都通过时采取的行为。

每个选项都可以选用以下的其中一种行为:
GL_KEEP 保持当前储存的模板值
GL_ZERO 将模板值设置为0
GL_REPLACE 将模板值设置为glStencilFunc函数设置的ref值
GL_INCR 如果模板值小于最大值则将模板值加1
GL_INCR_WRAP 与GL_INCR一样,但如果模板值超过了最大值则归零
GL_DECR 如果模板值大于最小值则将模板值减1
GL_DECR_WRAP 与GL_DECR一样,但如果模板值小于0则将其设置为最大值
GL_INVERT 按位翻转当前的模板缓冲值

默认情况下glStencilOp是设置为(GL_KEEP, GL_KEEP, GL_KEEP) 的,所以不论任何测试的结果是如何,模板缓冲都会保留它的值。默认的行为不会更新模板缓冲,所以如果你想写入模板缓冲的话,你需要至少对其中一个选项设置不同的值。

综上,通过使用glStencilFunc和glStencilOp,我们可以精确地指定更新模板缓冲的时机与行为了,我们也可以指定什么时候该让模板缓冲通过,即什么时候片段需要被丢弃。

物体轮廓

使用模板测试可以完成的有用特性,叫做物体轮廓

会为每个(或者一个)物体在它的周围创建一个很小的有色边框。当你想要在策略游戏中选中一个单位进行操作的,想要告诉玩家选中的是哪个单位的时候,这个效果就非常有用了。为物体创建轮廓的步骤如下:

  1. 在绘制(需要添加轮廓的)物体之前,将模板函数设置GL_ALWAYS,每当物体的片段被渲染时,将模板缓冲更新为1
  2. 渲染物体。
  3. 禁用模板写入以及深度测试
  4. 将每个物体缩放一点点。
  5. 使用一个不同的片段着色器,输出一个单独的(边框)颜色。
  6. 再次绘制物体,但只在它们片段的模板值不等于1时才绘制
  7. 再次启用模板写入和深度测试

创建一个很简单的片段着色器,它会输出一个边框颜色。我们简单地给它设置一个硬编码的颜色值,将这个着色器命名为shaderSingleColor:

void main()
{FragColor = vec4(0.04, 0.28, 0.26, 1.0);
}

首先绘制地板,再绘制两个箱子(并写入模板缓冲),之后绘制放大的箱子(并丢弃覆盖了之前绘制的箱子片段的那些片段)。
先启用模板测试,并设置测试通过或失败的行为:

glEnable(GL_STENCIL_TEST);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);

如果其中的一个测试失败了,我们什么都不做,我们仅仅保留当前储存在模板缓冲中的值。如果模板测试和深度测试都通过了,那么我们希望将储存的模板值设置为参考值,参考值能够通过glStencilFunc来设置,我们之后会设置为1。
我们将模板缓冲清除为0,对箱子中所有绘制的片段,将模板值更新为1:

glStencilFunc(GL_ALWAYS, 1, 0xFF); // 所有的片段都应该更新模板缓冲
glStencilMask(0xFF); // 启用模板缓冲写入
normalShader.use();
DrawTwoContainers();

通过使用GL_ALWAYS模板测试函数,我们保证了箱子的每个片段都会将模板缓冲的模板值更新为1。因为片段永远会通过模板测试,在绘制片段的地方,模板缓冲会被更新为参考值。

现在模板缓冲在箱子被绘制的地方都更新为1了,我们将要绘制放大的箱子,但这次要禁用模板缓冲的写入:

glStencilFunc(GL_NOTEQUAL, 1, 0xFF);
glStencilMask(0x00); // 禁止模板缓冲的写入
glDisable(GL_DEPTH_TEST);
shaderSingleColor.use(); 
DrawTwoScaledUpContainers();

我们将模板函数设置为GL_NOTEQUAL,它会保证我们只绘制箱子上模板值不为1的部分,即只绘制箱子在之前绘制的箱子之外的部分。注意我们也禁用了深度测试,让放大的箱子,即边框,不会被地板所覆盖
在完成之后重新启用深度缓冲。

完整步骤如下:

glEnable(GL_DEPTH_TEST);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glStencilMask(0x00); // 记得保证我们在绘制地板的时候不会更新模板缓冲
normalShader.use();
DrawFloor()  glStencilFunc(GL_ALWAYS, 1, 0xFF); 
glStencilMask(0xFF); 
DrawTwoContainers();glStencilFunc(GL_NOTEQUAL, 1, 0xFF);
glStencilMask(0x00); 
glDisable(GL_DEPTH_TEST);
shaderSingleColor.use(); 
DrawTwoScaledUpContainers();
glStencilMask(0xFF);
glEnable(GL_DEPTH_TEST);  

综上,代码如下:放大立方体,画边框地方需要仔细学习

#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <stb_image.h>#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>#include <learnopengl/shader_m.h>
#include <learnopengl/camera.h>
#include <learnopengl/model.h>#include <iostream>void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void processInput(GLFWwindow *window);
unsigned int loadTexture(const char *path);// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;// camera
Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));
float lastX = (float)SCR_WIDTH / 2.0;
float lastY = (float)SCR_HEIGHT / 2.0;
bool firstMouse = true;// timing
float deltaTime = 0.0f;
float lastFrame = 0.0f;int main()
{// glfw: initialize and configure// ------------------------------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 window creation// --------------------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);glfwSetCursorPosCallback(window, mouse_callback);glfwSetScrollCallback(window, scroll_callback);// tell GLFW to capture our mouseglfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);// glad: load all OpenGL function pointers// ---------------------------------------if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){std::cout << "Failed to initialize GLAD" << std::endl;return -1;}// configure global opengl state// -----------------------------glEnable(GL_DEPTH_TEST);glDepthFunc(GL_LESS);glEnable(GL_STENCIL_TEST);glStencilFunc(GL_NOTEQUAL, 1, 0xFF);glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);// build and compile shaders// -------------------------Shader shader("2.stencil_testing.vs", "2.stencil_testing.fs");Shader shaderSingleColor("2.stencil_testing.vs", "2.stencil_single_color.fs");// set up vertex data (and buffer(s)) and configure vertex attributes// ------------------------------------------------------------------float cubeVertices[] = {// positions          // texture Coords-0.5f, -0.5f, -0.5f,  0.0f, 0.0f,0.5f, -0.5f, -0.5f,  1.0f, 0.0f,0.5f,  0.5f, -0.5f,  1.0f, 1.0f,0.5f,  0.5f, -0.5f,  1.0f, 1.0f,-0.5f,  0.5f, -0.5f,  0.0f, 1.0f,-0.5f, -0.5f, -0.5f,  0.0f, 0.0f,-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,0.5f, -0.5f,  0.5f,  1.0f, 0.0f,0.5f,  0.5f,  0.5f,  1.0f, 1.0f,0.5f,  0.5f,  0.5f,  1.0f, 1.0f,-0.5f,  0.5f,  0.5f,  0.0f, 1.0f,-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,-0.5f,  0.5f,  0.5f,  1.0f, 0.0f,-0.5f,  0.5f, -0.5f,  1.0f, 1.0f,-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,-0.5f,  0.5f,  0.5f,  1.0f, 0.0f,0.5f,  0.5f,  0.5f,  1.0f, 0.0f,0.5f,  0.5f, -0.5f,  1.0f, 1.0f,0.5f, -0.5f, -0.5f,  0.0f, 1.0f,0.5f, -0.5f, -0.5f,  0.0f, 1.0f,0.5f, -0.5f,  0.5f,  0.0f, 0.0f,0.5f,  0.5f,  0.5f,  1.0f, 0.0f,-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,0.5f, -0.5f, -0.5f,  1.0f, 1.0f,0.5f, -0.5f,  0.5f,  1.0f, 0.0f,0.5f, -0.5f,  0.5f,  1.0f, 0.0f,-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,-0.5f,  0.5f, -0.5f,  0.0f, 1.0f,0.5f,  0.5f, -0.5f,  1.0f, 1.0f,0.5f,  0.5f,  0.5f,  1.0f, 0.0f,0.5f,  0.5f,  0.5f,  1.0f, 0.0f,-0.5f,  0.5f,  0.5f,  0.0f, 0.0f,-0.5f,  0.5f, -0.5f,  0.0f, 1.0f};float planeVertices[] = {// positions          // texture Coords (note we set these higher than 1 (together with GL_REPEAT as texture wrapping mode). this will cause the floor texture to repeat)5.0f, -0.5f,  5.0f,  2.0f, 0.0f,-5.0f, -0.5f,  5.0f,  0.0f, 0.0f,-5.0f, -0.5f, -5.0f,  0.0f, 2.0f,5.0f, -0.5f,  5.0f,  2.0f, 0.0f,-5.0f, -0.5f, -5.0f,  0.0f, 2.0f,5.0f, -0.5f, -5.0f,  2.0f, 2.0f};// cube VAOunsigned int cubeVAO, cubeVBO;glGenVertexArrays(1, &cubeVAO);glGenBuffers(1, &cubeVBO);glBindVertexArray(cubeVAO);glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), &cubeVertices, GL_STATIC_DRAW);glEnableVertexAttribArray(0);glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);glEnableVertexAttribArray(1);glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));glBindVertexArray(0);// plane VAOunsigned int planeVAO, planeVBO;glGenVertexArrays(1, &planeVAO);glGenBuffers(1, &planeVBO);glBindVertexArray(planeVAO);glBindBuffer(GL_ARRAY_BUFFER, planeVBO);glBufferData(GL_ARRAY_BUFFER, sizeof(planeVertices), &planeVertices, GL_STATIC_DRAW);glEnableVertexAttribArray(0);glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);glEnableVertexAttribArray(1);glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));glBindVertexArray(0);// load textures// -------------unsigned int cubeTexture = loadTexture(FileSystem::getPath("resources/textures/marble.jpg").c_str());unsigned int floorTexture = loadTexture(FileSystem::getPath("resources/textures/metal.png").c_str());// shader configuration// --------------------shader.use();shader.setInt("texture1", 0);// render loop// -----------while (!glfwWindowShouldClose(window)){// per-frame time logic// --------------------float currentFrame = static_cast<float>(glfwGetTime());deltaTime = currentFrame - lastFrame;lastFrame = currentFrame;// input// -----processInput(window);// render// ------glClearColor(0.1f, 0.1f, 0.1f, 1.0f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); // don't forget to clear the stencil buffer!// set uniformsshaderSingleColor.use();glm::mat4 model = glm::mat4(1.0f);glm::mat4 view = camera.GetViewMatrix();glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);shaderSingleColor.setMat4("view", view);shaderSingleColor.setMat4("projection", projection);shader.use();shader.setMat4("view", view);shader.setMat4("projection", projection);// draw floor as normal, but don't write the floor to the stencil buffer, we only care about the containers. We set its mask to 0x00 to not write to the stencil buffer.glStencilMask(0x00);// floorglBindVertexArray(planeVAO);glBindTexture(GL_TEXTURE_2D, floorTexture);shader.setMat4("model", glm::mat4(1.0f));glDrawArrays(GL_TRIANGLES, 0, 6);glBindVertexArray(0);// 1st. render pass, draw objects as normal, writing to the stencil buffer// --------------------------------------------------------------------glStencilFunc(GL_ALWAYS, 1, 0xFF);glStencilMask(0xFF);// cubesglBindVertexArray(cubeVAO);glActiveTexture(GL_TEXTURE0);glBindTexture(GL_TEXTURE_2D, cubeTexture);model = glm::translate(model, glm::vec3(-1.0f, 0.0f, -1.0f));shader.setMat4("model", model);glDrawArrays(GL_TRIANGLES, 0, 36);model = glm::mat4(1.0f);model = glm::translate(model, glm::vec3(2.0f, 0.0f, 0.0f));shader.setMat4("model", model);glDrawArrays(GL_TRIANGLES, 0, 36);// 2nd. render pass: now draw slightly scaled versions of the objects, this time disabling stencil writing.// Because the stencil buffer is now filled with several 1s. The parts of the buffer that are 1 are not drawn, thus only drawing // the objects' size differences, making it look like borders.// -----------------------------------------------------------------------------------------------------------------------------glStencilFunc(GL_NOTEQUAL, 1, 0xFF);glStencilMask(0x00);glDisable(GL_DEPTH_TEST);shaderSingleColor.use();float scale = 1.1f;// cubesglBindVertexArray(cubeVAO);glBindTexture(GL_TEXTURE_2D, cubeTexture);model = glm::mat4(1.0f);model = glm::translate(model, glm::vec3(-1.0f, 0.0f, -1.0f));model = glm::scale(model, glm::vec3(scale, scale, scale));shaderSingleColor.setMat4("model", model);glDrawArrays(GL_TRIANGLES, 0, 36);model = glm::mat4(1.0f);model = glm::translate(model, glm::vec3(2.0f, 0.0f, 0.0f));model = glm::scale(model, glm::vec3(scale, scale, scale));shaderSingleColor.setMat4("model", model);glDrawArrays(GL_TRIANGLES, 0, 36);glBindVertexArray(0);glStencilMask(0xFF);glStencilFunc(GL_ALWAYS, 0, 0xFF);glEnable(GL_DEPTH_TEST);// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)// -------------------------------------------------------------------------------glfwSwapBuffers(window);glfwPollEvents();}// optional: de-allocate all resources once they've outlived their purpose:// ------------------------------------------------------------------------glDeleteVertexArrays(1, &cubeVAO);glDeleteVertexArrays(1, &planeVAO);glDeleteBuffers(1, &cubeVBO);glDeleteBuffers(1, &planeVBO);glfwTerminate();return 0;
}// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// ---------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow *window)
{if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)glfwSetWindowShouldClose(window, true);if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)camera.ProcessKeyboard(FORWARD, deltaTime);if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)camera.ProcessKeyboard(BACKWARD, deltaTime);if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)camera.ProcessKeyboard(LEFT, deltaTime);if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)camera.ProcessKeyboard(RIGHT, deltaTime);
}// glfw: whenever the window size changed (by OS or user resize) this callback function executes
// ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{// make sure the viewport matches the new window dimensions; note that width and // height will be significantly larger than specified on retina displays.glViewport(0, 0, width, height);
}// glfw: whenever the mouse moves, this callback is called
// -------------------------------------------------------
void mouse_callback(GLFWwindow* window, double xposIn, double yposIn)
{float xpos = static_cast<float>(xposIn);float ypos = static_cast<float>(yposIn);if (firstMouse){lastX = xpos;lastY = ypos;firstMouse = false;}float xoffset = xpos - lastX;float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to toplastX = xpos;lastY = ypos;camera.ProcessMouseMovement(xoffset, yoffset);
}// glfw: whenever the mouse scroll wheel scrolls, this callback is called
// ----------------------------------------------------------------------
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{camera.ProcessMouseScroll(static_cast<float>(yoffset));
}// utility function for loading a 2D texture from file
// ---------------------------------------------------
unsigned int loadTexture(char const * 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::cout << "Texture failed to load at path: " << path << std::endl;stbi_image_free(data);}return textureID;
}

相关文章:

第十五章 opengl之高级OpenGL(模板测试)

OpenGL模板测试模板函数物体轮廓模板测试 当片段着色器处理完一个片段后&#xff0c;模板测试就会开始执行。类似于深度测试&#xff0c;模板测试也可能会丢弃片段。被保留的片段会进入深度测试&#xff0c;可能会丢弃更多的片段。 模板测试是根据模板缓冲来进行的。一个模板缓…...

【C语言蓝桥杯每日一题】—— 单词分析

【C语言蓝桥杯每日一题】—— 单词分析&#x1f60e;前言&#x1f64c;单词分析&#x1f64c;总结撒花&#x1f49e;&#x1f60e;博客昵称&#xff1a;博客小梦 &#x1f60a;最喜欢的座右铭&#xff1a;全神贯注的上吧&#xff01;&#xff01;&#xff01; &#x1f60a;作者…...

Web2:Tomcat

二.Web2&#xff1a;Tomcat 1.Tomcat的配置 2.Tomcat的工作方式 3.Tomcat服务器的虚拟映射 4.Tomcat部署到IDEA中使用 二.Web2&#xff1a;Tomcat 1.Tomcat的配置 ①安装下载Tomcat 配置好JAVA_HOME启动时保证端口号8080不被占用 ②下载后的目录结构 bin 启动或关闭to…...

C++语法规则2(C++面向对象)

继承 面向对象程序设计中最重要的一个概念是继承。继承允许我们依据另一个类来定义一个类&#xff0c;这使得创建和维护一个应用程序变得更容易。这样做&#xff0c;也达到了重用代码功能和提高执行效率的效果。 当创建一个类时&#xff0c;您不需要重新编写新的数据成员和成…...

第八批国家药品集中采购-(附药品集采目录明细下载)

2023年3月2日&#xff0c;‘国家组织药品联合采购办公室’发出了《全国药品集中采购文件》&#xff0c;宣告了第八批国家组织药品集中采购工作正式开展&#xff0c;其公告中还包含三个附表分别为‘采购品种目录’、‘各地区首年约定采购量’、‘各采购品种首年约定采购量’&…...

政府工作报告连提9年科技创新 企业研发如何“又快又好”

今年的政府工作报告&#xff0c; “科技创新” 这一描述连续出现7次&#xff0c;这也是自2015年开始&#xff0c; “科技创新” 这一概念在全国“两会”政府工作报告中连续九年被提到。政府工作报告指出&#xff0c;科技政策要聚焦自立自强&#xff0c;完善新型举国体制&#x…...

GM8773C 是一款 1:2 DSI 桥接芯片,可实现 4 路进 8 路出转换器功能、视频分离器功能。

GM8773C 是一款 1&#xff1a;2 DSI 桥接芯片&#xff0c;可实现 4 路进 8 路出转换器功能、视频分离器功能。芯片内集成了一个 4 路单一链路的 MIPI DSI 接收器和 8 路双链路 MIPI DSI 发送器。 接 收 器 每 路 可 以 支 持 到 2.0Gbps/lane &#xff0c; 可 以 最 高 支 持 到…...

Java常用包名和说明

包名主要功能java.applet提供了创建applet需要的所有类java.awt.*提供了创建用户界面以及绘制和管理图形、图像的类java.beans.*提供了开发Java Beans需要的所有类java.io提供了通过数据流、对象序列以及文件系统实现的系统输入、输出java.lang.*Java编程语言的基本类库java.ma…...

dva01-初识

背景 React 本身只是一个 DOM 的抽象层&#xff0c;使用组件构建虚拟 DOM。如果开发大应用&#xff0c;还需要解决一个问题。 通信&#xff1a;React 只提供了一种传参手段&#xff0c;后续数据变化非常麻烦&#xff0c;无法适用于大应用。数据流&#xff1a;每次要更新数据&…...

信捷 XDH Ethercat A_WRITE指令

本指令修改指令轴的当前位置。 什么时候需要用本指令呢&#xff1f;换句话说&#xff0c;用本指令后&#xff0c;坐标原点修改了偏移了。如果在回原点后&#xff0c;往前走了一段距离x,如果是用绝对模式执行把位置修改成0&#xff0c;那么下一次开始每次做绝对运动A_MOVEA&…...

Spring Cloud ( Eureka集群的搭建 )

操作步骤&#xff1a; 添加主机映射创建Eureka服务 导入依赖编写启动类编写yml复制服务实例测试一、添加主机映射 以 Windows系统为例&#xff0c;如果要构建集群&#xff0c;需要修改 hosts 文件&#xff0c;为其添加主机名的映射。 打开C:\Windows\System32\drivers\etc\h…...

Python re 模块

正则表达式是一种小型、高度专业化的编程语言。适用于任何语言&#xff0c;在 Python 中通过 re 模块实现。正则模式被编译成一系列的字节码&#xff0c;然后由 C 语言编写的匹配引擎执行。给字符串模糊匹配 正则用于匹配字符串&#xff0c;匹配字符串可以完全匹配和模糊匹配&…...

为什么越来越多的人开始学习大数据

因为根据国内的发展形势&#xff0c;大数据未来的发展前景会非常好&#xff0c;前景好需求高&#xff0c;自然会吸引越来越多的人进入大数据行业 我国市场环境处于急需大数据人才但人才不足的阶段&#xff0c;所以未来大数据领域会有很多的就业机遇。 2022年春季&#xff0c;…...

【C++】C++核心编程(二)---引用

1.基本语法 作用&#xff1a;给变量起别名 语法&#xff1a;数据类型 &别名 原名&#xff08;int &b a&#xff0c;其中别名与原名的数据类型必须一致&#xff09; 注意事项&#xff1a; 引用必须初始化引用在初始化后&#xff0c;就不可以再改变了 代码演示&am…...

原型设计模式

介绍 原型模式 在Java中,原型模式是一种创建型设计模式,它允许通过复制一个现有对象来创建一个新对象,而不是通过创建新的对象来初始化一个对象,原型模式是一种基于克隆的设计模式,通过复制现有对象的数据来创建新的对象. 原型模式需要实现Cloneable接口并重写Object类中的c…...

JVM结构-类加载(类加载子系统,类加载的角色,类加载的过程,类加载器分类,双亲委派机制,类的主/被动使用)

JVM 结构-类加载2.1类加载子系统2.2类加载的角色2.3类加载的过程2.3.1加载2.3.2链接2.3.3初始化2.4类加载器分类2.4.1 引导类加载器2.4.2扩展类加载器2.4.3应用程序类加载器2.5双亲委派机制2.6类的主动/被动使用2.1类加载子系统 类加载器子系统负责从文件系统或者网络中加载 cl…...

vcpkg私有port的创建和使用

1,准备环境: 系统:windows 系统 2, 安装vcpkg 步骤一 :先git clone下载下来vcpkg文件夹 命令:git clone “https://github.com/Microsoft/vcpkg.git” 步骤二:添加vcpkg环境变量 例如下载目录:D:\woker_zj 步骤三:编译vcpkg 操作:双击bootstrap-vcpkg.bat 步骤四: 为…...

LeetCode——203. 移除链表元素

对于初学链表的学者来学&#xff0c;链表是比较困难的&#xff0c;这部分对指针结构体的要求比较高。我们通过练习是掌握知识的重要途经203. 移除链表元素 - 力扣&#xff08;LeetCode&#xff09;我们在数组中去除某元素是遍历一遍数组&#xff0c;如果某位置是要去除的元素&a…...

[Java Web]Request对象 | 超1w字带你熟悉Servlet中的request请求

⭐作者介绍&#xff1a;大二本科网络工程专业在读&#xff0c;持续学习Java&#xff0c;输出优质文章 ⭐所属专栏&#xff1a;Java Web ⭐如果觉得文章写的不错&#xff0c;欢迎点个关注&#x1f609;有写的不好的地方也欢迎指正&#xff0c;一同进步&#x1f601; 目录 Reque…...

求一个补码表示数的原始值的三种方式

求一个补码表示数的原始值的三种方式假设 a(10010)2′complement−14a (10010)_{2complement}-14a(10010)2′complement​−14 方式1&#xff0c;通过补码求原始值公式求值&#xff08;see article&#xff09; x−xM−1∗2M−1∑i0M−2xi∗2ix-x_{M-1}*2^{M-1}\sum_{i0}^{M-2…...

【计算机组成原理】

第2章 运算方法和运算器 2.1 数据与文字的表示方法 2.1.1 数据格式 定点数的表示方法 定点纯小数纯小数表示范围定点纯整数定点表示法特点 浮点数的表示方法&#xff1a; 浮点的规格化表示&#xff1a;阶码、尾数、指数、基数IEEE754标准&#xff1a;单精度、双精度浮点数表…...

论文分享:图像识别与隐私安全

1、基于差分隐私框架的频域下人脸识别隐私保护算法Privacy-Preserving Face Recognition with Learnable Privacy Budget in Frequency Domain2、一种基于视觉密码学和可信计算的无密钥依赖的医学图像安全隐私保护框架A Privacy Protection Framework for Medical Image Securi…...

计算机基础小结

目录 ❤ 计算机基础编程 什么是编程语言? 什么是编程? 为什么要学习编程? ❤ 计算机组成原理 控制器 运算器 储存器 内存(主存) 外存 输入设备 输出设备 适配器 总线 机械硬盘 固态硬盘 ❤ 计算机操作系统 什么是操作系统? 什么是文件? 什么是应…...

Linux服务器还有漏洞?建议使用 OpenVAS 日常检查!

几乎每天都会有新的系统漏洞产生&#xff0c;系统管理员经常忙于管理服务器&#xff0c;有时候会忽略一些很明显的安全问题。扫描 Linux 服务器以查找安全问题并不是很简单的事情&#xff0c;所以有时候需要借助于一些专门的工具。 OpenVAS 就是这样一种开源工具&#xff0c;它…...

【Redis】P1 Redis - NoSQL

Redis - NoSQLSQL 与 NoSQL差别一&#xff1a;结构化 与 非结构化差别二&#xff1a;关联性 与 非关联性差别三&#xff1a;规范化查询语句 与 非规范化差别四&#xff1a;事务 与 无事务差别五&#xff1a;磁盘存储 与 内存存储RedisRedis 的安装当前数据库存储主要分为 关系型…...

Angular学习之ControlValueAccessor接口详解

ControlValueAccessor 是什么&#xff1f;为什么需要使用 &#xff1f;下面本篇文章就来带大家了解Angular中的ControlValueAccessor组件接口&#xff0c;希望对大家有所帮助&#xff01; ControlValueAccessor 是什么&#xff1f; 简单来说ControlValueAccessor是一个接口&am…...

【GORM】高级查询方案

【GORM】高级查询方案1.Struct & Map查询为空的情况2.FirstOrInit3.FirstOrCreate4.高级查询1.Struct & Map查询为空的情况 当通过结构体进行查询时&#xff0c;GORM将会只通过非零值字段查询&#xff0c;这意味着如果你的字段值为0&#xff0c;‘’&#xff0c;false…...

MFC 简单使用事件

功能三个按钮,一个静态框,默认值是0,增加减少按钮和退出按钮.增加减少按钮显示在静态框中.退出按钮退出软件.实验事件思路新建三个事件,add事件sub事件quit事件,一个按钮触发一个事件,静态框新建一个线程接受事件做出对应的改变.UI添加的代码就不具体说,具体说下事件的代码,这才…...

华为OD机试题 - 端口合并(JavaScript)| 机考必刷

更多题库,搜索引擎搜 梦想橡皮擦华为OD 👑👑👑 更多华为OD题库,搜 梦想橡皮擦 华为OD 👑👑👑 更多华为机考题库,搜 梦想橡皮擦华为OD 👑👑👑 华为OD机试题 最近更新的博客使用说明本篇题解:端口合并题目输入输出示例一输入输出说明示例二输入输出说明示例…...

ECharts数据可视化--常用图表类型

目录 一.柱状图 1.基本柱状图 1.1最简单的柱状图 ​编辑 1.2多系列柱状图 1.3柱状图的样式 &#xff08;1&#xff09;柱条样式 &#xff08;2&#xff09;柱条的宽度和高度 &#xff08;3&#xff09;柱条间距 &#xff08;4&#xff09;为柱条添加背景颜色 ​编辑 2.堆…...

Flutter面试题解析-GridView详解与应用

一、前言Flutter 作为时下最流行的技术之一&#xff0c;凭借其出色的性能以及抹平多端的差异优势&#xff0c;早已引起大批技术爱好者的关注&#xff0c;甚至一些 闲鱼 &#xff0c; 美团 &#xff0c; 腾讯 等大公司均已投入生产使用。虽然目前其生态还没有完全成熟&#xff0…...

最全的论文写作技巧(建议收藏)

近10年来&#xff0c;笔者有幸多次参与教学论文的评审工作&#xff0c;在此&#xff0c;特将教学论文写作的步骤及相关问题整理汇总如下&#xff1a; 一、选定论题 &#xff08;一&#xff09;论题在文中的地位与作用 严格地讲&#xff0c;论文写作是从选定论题开始的。选题…...

面向对象设计模式:设计模式分类(创建型、行为型、结构型)

1. 创建型设计模式 单例模式&#xff1a;https://blog.csdn.net/qq_44992559/article/details/129348686工厂模式&#xff1a;https://blog.csdn.net/qq_44992559/article/details/115222311抽象工厂模式&#xff1a;https://blog.csdn.net/qq_44992559/article/details/12934…...

MySQL数据库迁移

考试系统的数据库一直是在我自己的服务器上面的&#xff0c; 但是最近&#xff0c;自己的服务器马上要过期了&#xff0c;里面的MySQL数据需要迁移出来&#xff0c;放在另外一个服务器上面。百度了几篇教程&#xff0c;也没研究太多&#xff0c;选了一种比较简单的方式进行迁移…...

Docker:关于 Dockerfile 编写优化的一些笔记整理

写在前面 分享一些 Dickerfile 构建镜像优化方式的笔记理解不足小伙伴帮忙指正 对每个人而言&#xff0c;真正的职责只有一个&#xff1a;找到自我。然后在心中坚守其一生&#xff0c;全心全意&#xff0c;永不停息。所有其它的路都是不完整的&#xff0c;是人的逃避方式&#…...

个性化营销:您需要知道的信息

个性化营销在现代企业中风靡一时。我们将剖析您需要了解的有关个性化营销的信息&#xff0c;一起来了解一下吧。 什么是个性化营销&#xff1f; 个性化营销是一种一对一营销形式&#xff0c;它使用实时用户数据和分析来传递品牌信息并针对特定潜在客户。 它与传统营销不同&…...

栈和队列的相互实现

文章目录一、用栈实现队列入队&#xff1a;出队&#xff1a;Java代码实现&#xff1a;二、用队列实现栈入栈&#xff1a;出栈&#xff1a;Java代码实现&#xff1a;附&#xff1a;C版代码1、用栈实现队列2、用队列实现栈栈&#xff08;stack&#xff09;&#xff1a;先进后出&a…...

iTab新标签页重磅更新 |这些功能绝对有你想要的新体验!

01 写在前面 csdn的朋友们&#xff0c;你好哦&#xff0c;我是iTab 插件的独立开发者&#xff0c;今天给大家安利一下我做的这款桌面插件。 首先要告诉大家一个好消息&#xff1a; 最近iTab新标签页被Edge 浏览器商店官方热门&#x1f525;推荐啦。 在此&#xff0c;特别感谢…...

【改机教程】iOS系统去除小黑条,改拍照声、拨号音、键盘音,不用越狱,支持所有机型

大家好&#xff0c;上次给大家分享了几个iOS系统免越狱改机教程 今天带来最新的教程&#xff0c;这次修改利用的是同一个漏洞&#xff0c;由外网大神 tamago 开发&#xff0c;国内大神冷风 进行汉化和优化 可以修改的地方包括 去除底部小黑条 dock栏透明 桌面文件夹透明 桌面…...

Android10开机向导中复用设置中的Wifi界面

很多时候我们需要定制开机向导&#xff0c;在开机向导界面我们一般会实现联网和设置时间等功能&#xff0c;考虑复用与稳定性问题&#xff0c;我们最好复用设置中的WiFi设置和日期设置。但是设置中的wifi设置界面默认是没有下一步按钮的&#xff0c;这会让用户感觉很奇怪。在以…...

川农机械专业小伙转行Java开发,年薪20w

本期学员就业故事&#xff0c;知了姐邀请到一位“特别”的同学&#xff0c;一位从知了堂就业成功近两年的学员再度接受我们的采访。 来自四川农业大学的曾同学&#xff0c;一个本来学机械开挖掘机的粗犷男人&#xff0c;因为不断地努力学习编程&#xff0c;最终成为一个性格闷…...

华为OD机试题 - 打印文件(JavaScript)| 机考必刷

更多题库,搜索引擎搜 梦想橡皮擦华为OD 👑👑👑 更多华为OD题库,搜 梦想橡皮擦 华为OD 👑👑👑 更多华为机考题库,搜 梦想橡皮擦华为OD 👑👑👑 华为OD机试题 最近更新的博客使用说明本篇题解:打印文件题目输入输出示例一输入输出示例二输入输出Code代码解析…...

免费常用API大全,程序员必备

淘宝接口 淘宝开放平台 http://open.taobao.com/?spma219a.7395905.1.1.YdFDV6 APISpace 生活常用 今天吃什么&#xff1a;随机返回一顿美味食物&#xff0c;解决你今天吃什么的难题。 星座查询&#xff1a;根据日期或星座名称&#xff0c;查询星座详细信息&#xff0c;包…...

MySQL主从复制,读写分离

目录 一、MySQL主从复制介绍 MySQL复制过程分成三步 二、主库配置master 1、步骤1 2、第二步:重启Mysql服务 3、第三步&#xff1a;登录Mysql数据库&#xff0c;执行下面SQL 4、第四步&#xff1a;登录Mysql数据库&#xff0c;执行下面SQL&#xff0c;记录下结果中File和…...

什么是UEFI签名认证?UEFI签名有什么好处?

为了防御恶意软件攻击&#xff0c;目前市面上所有电脑设备启动时默认开启安全启动(Secure Boot)模式。安全启动(Secure Boot)是UEFI扩展协议定义的安全标准&#xff0c;可以确保设备只使用OEM厂商信任的软件启动。UEFI签名认证就是对运行在 UEFI 系统下的 efi 驱动和通过 UEFI …...

案例14-课程推送页面逻辑整理--vue

目录一级目录二级目录三级目录一、背景介绍二、问题分析问题1&#xff1a;逻辑边界不清晰&#xff0c;封装意识缺乏问题问题2&#xff1a;展示效果上的问题三、解决过程问题一 代码结构混乱问题解决问题二 代码结构混乱问题解决问题三 展示效果上的细微问题四、总结一级目录 二…...

5大GPU厂商共建 | openKylin社区GPU SIG首次例会召开!

3月8日&#xff0c;openKylin社区GPU SIG首次例会以线上形式召开。此次会议由长沙景美集成电路设计有限公司、摩尔线程智能科技&#xff08;北京&#xff09;有限责任公司、格兰菲智能科技有限公司、象帝先计算技术&#xff08;重庆&#xff09;有限公司等GPU厂商的多位SIG Mai…...

SpringBoot读取配置文件

目录一、简介1、SpringBoot 中常用读取配置方法2、 ConfigurationProperties和Value的区别二、使用 ConfigurationProperties 读取配置三、使用 Value 读取配置一、简介 在日常开发使用 SpringBoot 框架时&#xff0c;经常有一些配置信息需要放置到配置文件中&#xff0c;我们…...

51驱动NRF24L01通信,NRF24L01与TTL转NRF24L01模块通信

51驱动NRF24L01通信&#xff0c;NRF24L01与TTL转NRF24L01模块通信NRF24L01一、简介二、引脚功能描述程序设计一、对 24L01 的程序编程的基本思路如下&#xff1a;二、Tx 与 Rx 的配置过程1、Tx 模式初始化过程&#xff1a;2、Rx 模式初始化过程&#xff1a;三、基本程序函数通信…...

C++友元

欢迎来观看温柔了岁月.c的博客 目前 设有C学习专栏 C语言项目专栏 数据结构与算法专栏 目前主要更新C学习专栏&#xff0c;C语言项目专栏不定时更新 待C专栏完毕&#xff0c;会陆续更新C项目专栏和数据结构与算法专栏 一周主要三更&#xff0c;星期三&#xff0c;星期五&#x…...