(十三)MipMap

MipMap概念

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

滤波

在这里插入图片描述

采样

在这里插入图片描述
在这里插入图片描述

mipmap级别判定

问题:opengl如何判定应该使用下一级的mipmap呢?
通过glsl中的求偏导函数计算变化量决定
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

手动实现mipmap原理

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
1、生成mipmap的各个级别
2、修改vertexShader使得三角形随着时间变小
**** 需要更改Filter才能够在变小的时候使用mipmap *****

#include <glad/glad.h>//glad必须在glfw头文件之前包含
#include <GLFW/glfw3.h>
#include <iostream>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
void frameBufferSizeCallbakc(GLFWwindow* window, int width, int height)
{
	glViewport(0, 0, width, height);
}
void glfwKeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
}

GLuint program = 0;
GLuint vao = 0;
void prepareVAO()
{
	//positions
	float positions[] = {
		-0.5f, -0.5f, 0.0f,
		0.5f, -0.5f, 0.0f,
		0.0f,  0.5f, 0.0f,
	};
	//颜色
	float colors[] = {
		1.0f, 0.0f,0.0f,
		0.0f, 1.0f,0.0f,
		0.0f, 0.0f,1.0f,
	};
	//索引
	unsigned int indices[] = {
		0, 1, 2,
	};
	//uv坐标
	float uvs[] = {
		0.0f, 0.0f,
		1.0f, 0.0f,
		0.5f, 1.0f,
	};

	//2 VBO创建
	GLuint posVbo = 0;
	GLuint colorVbo = 0;
	GLuint uvVbo = 0;
	glGenBuffers(1, &posVbo);
	glBindBuffer(GL_ARRAY_BUFFER, posVbo);
	glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);

	glGenBuffers(1, &colorVbo);
	glBindBuffer(GL_ARRAY_BUFFER, colorVbo);
	glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);

	glGenBuffers(1, &uvVbo);
	glBindBuffer(GL_ARRAY_BUFFER, uvVbo);
	glBufferData(GL_ARRAY_BUFFER, sizeof(uvs), uvs, GL_STATIC_DRAW);

	//3 EBO创建
	GLuint ebo = 0;
	glGenBuffers(1, &ebo);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

	//4 VAO创建
	vao = 0;
	glGenVertexArrays(1, &vao);
	glBindVertexArray(vao);

	//5 绑定vbo ebo 加入属性描述信息
	//5.1 加入位置属性描述信息
	glBindBuffer(GL_ARRAY_BUFFER, posVbo);
	glEnableVertexAttribArray(0);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);

	//5.2 加入颜色属性描述信息
	glBindBuffer(GL_ARRAY_BUFFER, colorVbo);
	glEnableVertexAttribArray(1);
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);

	//5.3 加入uv属性描述数据
	glBindBuffer(GL_ARRAY_BUFFER, uvVbo);
	glEnableVertexAttribArray(2);
	glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);

	//5.2 加入ebo到当前的vao
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);

	glBindVertexArray(0);
}
void prepareShader() {
	//1 完成vs与fs的源代码,并且装入字符串
	const char* vertexShaderSource =
		"#version 330 core\n"
		"layout (location = 0) in vec3 aPos;\n"
		"layout (location = 1) in vec3 aColor;\n"
		"layout (location = 2) in vec2 aUV;\n"
		"out vec3 color;\n"
		"out vec2 uv;\n"
		"uniform float time;\n"
		"void main()\n"
		"{\n"
		"   float scale = 1.0/time;\n"
		"   vec3 sPos = aPos * scale;\n"
		"   gl_Position = vec4(sPos, 1.0);\n"
		"   color = aColor;\n"
		"   uv = aUV;\n"
		"}\0";
	const char* fragmentShaderSource =
		"#version 330 core\n"
		"out vec4 FragColor;\n"
		"in vec3 color;\n"
		"in vec2 uv;\n"
		"uniform sampler2D sampler;\n"
		"void main()\n"
		"{\n"
		"  FragColor = texture(sampler, uv);\n"
		"}\n\0";


	//2 创建Shader程序(vs、fs)
	GLuint vertex, fragment;
	vertex = glCreateShader(GL_VERTEX_SHADER);
	fragment = glCreateShader(GL_FRAGMENT_SHADER);


	//3 为shader程序输入shader代码
	glShaderSource(vertex, 1, &vertexShaderSource, NULL);
	glShaderSource(fragment, 1, &fragmentShaderSource, NULL);

	int success = 0;
	char infoLog[1024];
	//4 执行shader代码编译 
	glCompileShader(vertex);
	//检查vertex编译结果
	glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
	if (!success) {
		glGetShaderInfoLog(vertex, 1024, NULL, infoLog);
		std::cout << "Error: SHADER COMPILE ERROR --VERTEX" << "\n" << infoLog << std::endl;
	}

	glCompileShader(fragment);
	//检查fragment编译结果
	glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
	if (!success) {
		glGetShaderInfoLog(fragment, 1024, NULL, infoLog);
		std::cout << "Error: SHADER COMPILE ERROR --FRAGMENT" << "\n" << infoLog << std::endl;
	}

	//5 创建一个Program壳子
	program = glCreateProgram();

	//6 将vs与fs编译好的结果放到program这个壳子里
	glAttachShader(program, vertex);
	glAttachShader(program, fragment);

	//7 执行program的链接操作,形成最终可执行shader程序
	glLinkProgram(program);

	//检查链接错误
	glGetProgramiv(program, GL_LINK_STATUS, &success);
	if (!success) {
		glGetProgramInfoLog(program, 1024, NULL, infoLog);
		std::cout << "Error: SHADER LINK ERROR " << "\n" << infoLog << std::endl;
	}

	//清理
	glDeleteShader(vertex);
	glDeleteShader(fragment);
}
GLuint genTexture(const char* picPath, int unitTexturt)
{
	//1 stbImage 读取图片
	int width, height, channels;
	//--反转y轴
	stbi_set_flip_vertically_on_load(true);
	unsigned char* data = stbi_load(picPath, &width, &height, &channels, STBI_rgb_alpha);

	//2 生成纹理并且激活单元绑定
	GLuint texture = 0;
	glGenTextures(1, &texture);
	//--激活纹理单元--
	glActiveTexture(GL_TEXTURE0 + unitTexturt);
	//--绑定纹理对象--
	glBindTexture(GL_TEXTURE_2D, texture);

	int tmepWidth = width, tempHeight = height;
	//3 传输纹理数据,开辟显存
	//glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
	//遍历每个mipmap的层级,为每个级别的mipmap填充图片数据
	for (int level = 0; true; ++level)
	{
		//1 将当前级别的mipmap对应的数据发往gpu端
		glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, tmepWidth, tempHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
		//2 判断是否退出循环
		if (tmepWidth == 1 && tempHeight == 1)
			break;
		//3 计算下一次循环的宽度/高度,除以2
		tmepWidth = tmepWidth > 1 ? tmepWidth / 2 : 1;
		tempHeight = tempHeight > 1 ? tempHeight / 2 : 1;
	}

	//***释放数据
	stbi_image_free(data);

	//4 设置纹理的过滤方式
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	//*****重要*****//
	//GL_NEAREST:在单个mipmap上采用最邻近采样
	//GL_LINEAR   
	//MIPMAP_LINEAR:在两层mipmap之间采用线性插值
	//MIPMAP_NEAREST
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);

	//5 设置纹理的包裹方式
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);//u
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);//v

	return texture;
}
void prepareTextrue()
{
	//GLuint grassTexture = genTexture("grass.jpg", 0);
	//GLuint landTexture = genTexture("land.jpg", 1);
	//GLuint noiseTexture = genTexture("noise.jpg", 2);
	GLuint wallTexture = genTexture("goku.jpg", 0);
}

void render()
{
	//执行opengl画布清理操作
	glClear(GL_COLOR_BUFFER_BIT);

	//1.绑定当前的program
	glUseProgram(program);

	//2 更新Uniform的时候,一定要先UserProgram
	//2.1 通过名称拿到Uniform变量的位置Location
	//2.2 通过Location更新Uniform变量的值
	GLint time = glGetUniformLocation(program, "time");
	int i = glfwGetTime();
	glUniform1f(time, glfwGetTime());
	GLint sampler = glGetUniformLocation(program, "sampler");
	glUniform1i(sampler, 0);
	

	//3 绑定当前的vao
	glBindVertexArray(vao);
	//4 发出绘制指令
	//glDrawArrays(GL_TRIANGLE_STRIP, 0, 6);
	glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0);
}


int main()
{
	//初始化glfw环境
	glfwInit();
	//设置opengl主版本号
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	//设置opengl次版本号
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	//设置opengl启用核心模式
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

	//创建窗体对象
	GLFWwindow* window = glfwCreateWindow(800, 600, "lenarnOpenGL", nullptr, nullptr);
	//设置当前窗体对象为opengl的绘制舞台
	glfwMakeContextCurrent(window);
	//窗体大小回调
	glfwSetFramebufferSizeCallback(window, frameBufferSizeCallbakc);
	//键盘相应回调
	glfwSetKeyCallback(window, glfwKeyCallback);

	//使用glad加载所有当前版本opengl的函数
	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
	{
		std::cout << "初始化glad失败" << std::endl;
		return -1;
	}
	;
	//设置opengl视口大小和清理颜色
	glViewport(0, 0, 800, 600);
	glClearColor(0.2f, 0.3f, 0.3f, 1.0f);

	//shader
	prepareShader();
	//vao
	prepareVAO();
	//texture
	prepareTextrue();

	//执行窗体循环
	while (!glfwWindowShouldClose(window))
	{
		//接受并分发窗体消息
		//检查消息队列是否有需要处理的鼠标、键盘等消息
		//如果有的话就将消息批量处理,清空队列
		glfwPollEvents();
		//渲染操作
		render();
		//切换双缓存
		glfwSwapBuffers(window);
	}

	//推出程序前做相关清理
	glfwTerminate();
	return 0;
}

上述代码即可实现随着时间的变化,不同层级的图片贴到三角形中的效果。
还可以不在代码中设置层级间的采样方式 即注释掉

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);

在fs中,实现根据像素对应图素的数量多少,决定采样哪个层级的mipmap

#version 330 core
out vec4 FragColor;
in vec3 color;
in vec2 uv;
uniform sampler2D sampler;
uniform float width;
uniform float height;
void main()
{
  //FragColor = texture(sampler, uv);

  //1 获取当前像素对应的纹理上的纹素具体位置
  vec2 location = uv * vec2(width, height);

  //2 计算当前像素对应纹素具体位置在xy方向上的变化量
  vec2 dx = dFdx(location);
  vec2 dy = dFdy(location);

  //3 选择最大的delta,求log2(delta)
  float maxDelta = sqrt(max(dot(dx, dx), dot(dy,dy)));
  float L = log2(maxDelta);

  //4 计算出mipmap的采样级别
  int level = max(int(L + 0.5), 0);

  FragColor = textureLod(sampler, uv, level);
}

fs的glsl设置以上字符串,渲染时设置图片的宽度和高度即可达到同样的效果。

opengl自动生成mipmap

在这里插入图片描述

#include <glad/glad.h>//glad必须在glfw头文件之前包含
#include <GLFW/glfw3.h>
#include <iostream>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
void frameBufferSizeCallbakc(GLFWwindow* window, int width, int height)
{
	glViewport(0, 0, width, height);
}
void glfwKeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
}

GLuint program = 0;
GLuint vao = 0;
void prepareVAO()
{
	//positions
	float positions[] = {
		-0.5f, -0.5f, 0.0f,
		0.5f, -0.5f, 0.0f,
		0.0f,  0.5f, 0.0f,
	};
	//颜色
	float colors[] = {
		1.0f, 0.0f,0.0f,
		0.0f, 1.0f,0.0f,
		0.0f, 0.0f,1.0f,
	};
	//索引
	unsigned int indices[] = {
		0, 1, 2,
	};
	//uv坐标
	float uvs[] = {
		0.0f, 0.0f,
		1.0f, 0.0f,
		0.5f, 1.0f,
	};

	//2 VBO创建
	GLuint posVbo = 0;
	GLuint colorVbo = 0;
	GLuint uvVbo = 0;
	glGenBuffers(1, &posVbo);
	glBindBuffer(GL_ARRAY_BUFFER, posVbo);
	glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);

	glGenBuffers(1, &colorVbo);
	glBindBuffer(GL_ARRAY_BUFFER, colorVbo);
	glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);

	glGenBuffers(1, &uvVbo);
	glBindBuffer(GL_ARRAY_BUFFER, uvVbo);
	glBufferData(GL_ARRAY_BUFFER, sizeof(uvs), uvs, GL_STATIC_DRAW);

	//3 EBO创建
	GLuint ebo = 0;
	glGenBuffers(1, &ebo);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

	//4 VAO创建
	vao = 0;
	glGenVertexArrays(1, &vao);
	glBindVertexArray(vao);

	//5 绑定vbo ebo 加入属性描述信息
	//5.1 加入位置属性描述信息
	glBindBuffer(GL_ARRAY_BUFFER, posVbo);
	glEnableVertexAttribArray(0);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);

	//5.2 加入颜色属性描述信息
	glBindBuffer(GL_ARRAY_BUFFER, colorVbo);
	glEnableVertexAttribArray(1);
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);

	//5.3 加入uv属性描述数据
	glBindBuffer(GL_ARRAY_BUFFER, uvVbo);
	glEnableVertexAttribArray(2);
	glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);

	//5.2 加入ebo到当前的vao
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);

	glBindVertexArray(0);
}
void prepareShader() {
	//1 完成vs与fs的源代码,并且装入字符串
	const char* vertexShaderSource =
		"#version 330 core\n"
		"layout (location = 0) in vec3 aPos;\n"
		"layout (location = 1) in vec3 aColor;\n"
		"layout (location = 2) in vec2 aUV;\n"
		"out vec3 color;\n"
		"out vec2 uv;\n"
		"uniform float time;\n"
		"void main()\n"
		"{\n"
		"   float scale = 1.0/time;\n"
		"   vec3 sPos = aPos * scale;\n"
		"   gl_Position = vec4(sPos, 1.0);\n"
		"   color = aColor;\n"
		"   uv = aUV;\n"
		"}\0";
	const char* fragmentShaderSource =
		"#version 330 core\n"
		"out vec4 FragColor;\n"
		"in vec3 color;\n"
		"in vec2 uv;\n"
		"uniform sampler2D sampler;\n"
		"void main()\n"
		"{\n"
		"  FragColor = texture(sampler, uv);\n"
		"}\n\0";


	//2 创建Shader程序(vs、fs)
	GLuint vertex, fragment;
	vertex = glCreateShader(GL_VERTEX_SHADER);
	fragment = glCreateShader(GL_FRAGMENT_SHADER);


	//3 为shader程序输入shader代码
	glShaderSource(vertex, 1, &vertexShaderSource, NULL);
	glShaderSource(fragment, 1, &fragmentShaderSource, NULL);

	int success = 0;
	char infoLog[1024];
	//4 执行shader代码编译 
	glCompileShader(vertex);
	//检查vertex编译结果
	glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
	if (!success) {
		glGetShaderInfoLog(vertex, 1024, NULL, infoLog);
		std::cout << "Error: SHADER COMPILE ERROR --VERTEX" << "\n" << infoLog << std::endl;
	}

	glCompileShader(fragment);
	//检查fragment编译结果
	glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
	if (!success) {
		glGetShaderInfoLog(fragment, 1024, NULL, infoLog);
		std::cout << "Error: SHADER COMPILE ERROR --FRAGMENT" << "\n" << infoLog << std::endl;
	}

	//5 创建一个Program壳子
	program = glCreateProgram();

	//6 将vs与fs编译好的结果放到program这个壳子里
	glAttachShader(program, vertex);
	glAttachShader(program, fragment);

	//7 执行program的链接操作,形成最终可执行shader程序
	glLinkProgram(program);

	//检查链接错误
	glGetProgramiv(program, GL_LINK_STATUS, &success);
	if (!success) {
		glGetProgramInfoLog(program, 1024, NULL, infoLog);
		std::cout << "Error: SHADER LINK ERROR " << "\n" << infoLog << std::endl;
	}

	//清理
	glDeleteShader(vertex);
	glDeleteShader(fragment);
}
GLuint genTexture(const char* picPath, int unitTexturt)
{
	//1 stbImage 读取图片
	int width, height, channels;
	//--反转y轴
	stbi_set_flip_vertically_on_load(true);
	unsigned char* data = stbi_load(picPath, &width, &height, &channels, STBI_rgb_alpha);

	//2 生成纹理并且激活单元绑定
	GLuint texture = 0;
	glGenTextures(1, &texture);
	//--激活纹理单元--
	glActiveTexture(GL_TEXTURE0 + unitTexturt);
	//--绑定纹理对象--
	glBindTexture(GL_TEXTURE_2D, texture);
	
	//3 传输纹理数据,开辟显存
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);

	//为当前纹理对象生成mipmap
	glGenerateMipmap(GL_TEXTURE_2D);

	//***释放数据
	stbi_image_free(data);

	//4 设置纹理的过滤方式
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	//*****重要*****//
	//GL_NEAREST:在单个mipmap上采用最邻近采样
	//GL_LINEAR   
	//MIPMAP_LINEAR:在两层mipmap之间采用线性插值
	//MIPMAP_NEAREST
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);

	//5 设置纹理的包裹方式
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);//u
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);//v

	return texture;
}
void prepareTextrue()
{
	//GLuint grassTexture = genTexture("grass.jpg", 0);
	//GLuint landTexture = genTexture("land.jpg", 1);
	//GLuint noiseTexture = genTexture("noise.jpg", 2);
	GLuint wallTexture = genTexture("goku.jpg", 0);
}

void render()
{
	//执行opengl画布清理操作
	glClear(GL_COLOR_BUFFER_BIT);

	//1.绑定当前的program
	glUseProgram(program);

	//2 更新Uniform的时候,一定要先UserProgram
	//2.1 通过名称拿到Uniform变量的位置Location
	//2.2 通过Location更新Uniform变量的值
	GLint time = glGetUniformLocation(program, "time");
	int i = glfwGetTime();
	glUniform1f(time, glfwGetTime());
	GLint sampler = glGetUniformLocation(program, "sampler");
	glUniform1i(sampler, 0);

	//3 绑定当前的vao
	glBindVertexArray(vao);
	//4 发出绘制指令
	//glDrawArrays(GL_TRIANGLE_STRIP, 0, 6);
	glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0);
}


int main()
{
	//初始化glfw环境
	glfwInit();
	//设置opengl主版本号
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	//设置opengl次版本号
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	//设置opengl启用核心模式
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

	//创建窗体对象
	GLFWwindow* window = glfwCreateWindow(800, 600, "lenarnOpenGL", nullptr, nullptr);
	//设置当前窗体对象为opengl的绘制舞台
	glfwMakeContextCurrent(window);
	//窗体大小回调
	glfwSetFramebufferSizeCallback(window, frameBufferSizeCallbakc);
	//键盘相应回调
	glfwSetKeyCallback(window, glfwKeyCallback);

	//使用glad加载所有当前版本opengl的函数
	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
	{
		std::cout << "初始化glad失败" << std::endl;
		return -1;
	}
	;
	//设置opengl视口大小和清理颜色
	glViewport(0, 0, 800, 600);
	glClearColor(0.2f, 0.3f, 0.3f, 1.0f);

	//shader
	prepareShader();
	//vao
	prepareVAO();
	//texture
	prepareTextrue();

	//执行窗体循环
	while (!glfwWindowShouldClose(window))
	{
		//接受并分发窗体消息
		//检查消息队列是否有需要处理的鼠标、键盘等消息
		//如果有的话就将消息批量处理,清空队列
		glfwPollEvents();
		//渲染操作
		render();
		//切换双缓存
		glfwSwapBuffers(window);
	}

	//推出程序前做相关清理
	glfwTerminate();
	return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

《昇思25天学习打卡营第8天|模型训练》

文章目录 今日所学&#xff1a;一、构建数据集二、定义神经网络模型三、了解超参、损失函数和优化器1. 超参2. 损失函数3. 优化器 四、训练与评估总结 今日所学&#xff1a; 在今天这一节我主要学习了模型的训练&#xff0c;知道了模型训练一般分为四个步骤&#xff1a; 构建…

[C++]——同步异步日志系统(2)

同步异步日志系统 一、 不定参函数1.1 不定参宏函数的使用1.2 C 语言中不定参函数的使用1.3 C不定参数使用 二、设计模式2.1 单列模式2.2 工厂模式2.3 建造者模式2.4 代理模式 在我们开发同步异步日志系统之前&#xff0c;需要了解一些相关的技术知识。 一、 不定参函数 在初学…

华为OD机试 - 考古学家 - 递归(Java 2024 D卷 200分)

华为OD机试 2024D卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;D卷C卷A卷B卷&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;每一题都有详细的答题思路、详细的代码注释、样例测…

p6spy 组件打印完整的 SQL 语句、执行耗时

一、前言 我们来配置一下 Mybatis Plus 打印 SQL 功能&#xff08;包括执行耗时&#xff09;&#xff0c;一方面可以了解到每个操作都具体执行的什么 SQL 语句&#xff0c; 另一方面通过打印执行耗时&#xff0c;也可以提前发现一些慢 SQL&#xff0c;提前做好优化&#xff0c…

西门子继裁员4100人计划后,巨资开启万人招聘!46万员工再增员……

导语 大家好&#xff0c;我是社长&#xff0c;老K。专注分享智能制造和智能仓储物流等内容。 新书《智能物流系统构成与技术实践》 更多的海量【智能制造】相关资料&#xff0c;请到智能制造online知识星球自行下载。 近年来&#xff0c;西门子在全球范围内继续扩大其业务规模。…

leetcode--二叉树中的最长交错路径

leetcode地址&#xff1a;二叉树中的最长交错路径 给你一棵以 root 为根的二叉树&#xff0c;二叉树中的交错路径定义如下&#xff1a; 选择二叉树中 任意 节点和一个方向&#xff08;左或者右&#xff09;。 如果前进方向为右&#xff0c;那么移动到当前节点的的右子节点&…

《vue3》reactivity API(vue3的$set呢?)

在Vue2中&#xff0c;修改某一些数据&#xff0c;视图是不能及时重新渲染的。 比如数组 <div> {{ myHobbies }} </div>data: () > ({myHobbies: [篮球, 羽毛球, 桌球] }); mounted () {this.myHobbies[1] sing; // 视图层并没有改变 }因此&#xff0c;Vue2就提…

实验2 字符及字符串输入输出与分支程序设计实验

字符及字符串输入输出 从键盘输入两个一位十进制数&#xff0c;计算这两个数之和&#xff0c;并将结果在屏幕上显示出来。 分支程序设计 从键盘输入一字符&#xff0c;判断该字符是小写字母、大写字母、数字或者其他字符。若输入为小写字母&#xff0c;显示“You Input a Lo…

无忧易售功能:刊登页面文本翻译,无缝对接全球买家

每一个词语&#xff0c;每一句话&#xff0c;都承载着产品的灵魂和品牌的故事&#xff0c;无忧易售的刊登页面文本翻译服务&#xff0c;一键操作即可将你的产品介绍、详情或广告文案转化为多语言版本&#xff0c;轻松管理&#xff0c;高效发布。 一、Allegro、OZON、Coupang、…

手动将dingtalk-sdk-java jar包打入maven本地仓库

有时候,中央镜像库不一定有自己需要的jar包,这时候我们就需要用到该方法,将jar打入maven本地仓库,然后项目中,正常使用maven的引入规则。 mvn install:install-file -Dmaven.repo.local=D:\software\maven\apache-maven-3.6.3-bin\apache-maven-3.6.3\repo -DgroupId=ding…

高德地图轨迹回放并提示具体信息

先上效果图 到达某地点后显示提示语&#xff1a;比如&#xff1a;12&#xff1a;56分驶入康庄大道、左转驶入xx大道等 <!doctype html> <html> <head><meta charset"utf-8"><meta http-equiv"X-UA-Compatible" content"…

Datawhale AI夏令营2024 Task3

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 #AI夏令营 #Datawhale #夏令营 一、数据集制作1.1 环境配置1.2 数据处理prompt1.3 训练数据集制作1.4 测试集数据制作 二、模型微调2.1 平台微调2.2 平台微调 三、微调推理提…

天环公益原创开发进度网站源码带后台免费分享

天环公益计划首发原创开发进度网站源码带后台免费分享 后台地址是&#xff1a;admin.php 后台没有账号密码 这个没有数据库 有能力的可以自己改 天环公益原创开发进度网站 带后台

【Vue】使用html、css实现鱼骨组件

文章目录 组件测试案例预览图 组件 <template><div class"context"><div class"top"><div class"label-context"><div class"label" v-for"(item, index) in value" :key"index">…

深度解析Java世界中的对象镜像:浅拷贝与深拷贝的奥秘与应用

在Java编程的浩瀚宇宙中&#xff0c;对象拷贝是一项既基础又至关重要的技术。它直接关系到程序的性能、资源管理及数据安全性。然而&#xff0c;提及对象拷贝&#xff0c;不得不深入探讨其两大核心类型&#xff1a;浅拷贝&#xff08;Shallow Copy&#xff09;与深拷贝&#xf…

【ROS2】初级:CLI工具-使用 rqt_console 查看日志

目标&#xff1a;了解 rqt_console &#xff0c;一种用于内省日志消息的工具。 教程级别&#xff1a;初学者 时间&#xff1a;5 分钟 目录 背景 先决条件 任务 设置在 rqt_console 上的 2 条消息 日志级别 3 摘要 下一步 背景 rqt_console 是用于在 ROS 2 中内省日志消息的 GUI…

【Python实战因果推断】21_倾向分1

目录 The Impact of Management Training Adjusting with Regression 之前学习了如何使用线性回归调整混杂因素。此外&#xff0c;还向您介绍了通过正交化去偏差的概念&#xff0c;这是目前最有用的偏差调整技术之一。不过&#xff0c;您还需要学习另一种技术--倾向加权。这种…

东哥教你如何用Orange Ai pro为家里做一个垃圾分类检测机器

前言 最近入手了一块香橙派&#xff08;Orange Ai Pro&#xff09;的板子&#xff0c;他们的口号是&#xff1a;为AI而生&#xff0c;这让一个算法工程师按捺不住了&#xff0c; 之前主要是在RKNN和ESP32等设备上部署AI模型&#xff0c;看到官方介绍的强大AI算力&#xff0c;很…

how to use Xcode

Xcode IDE概览 Xcode 页面主要分为以下四个部分&#xff1a; 工具栏&#xff08;ToolBar area&#xff09;&#xff1a;主要负责程序运行调试&#xff0c;编辑器功能区域的显示 / 隐藏&#xff1b;编辑区&#xff08;Editor area&#xff09;&#xff1a;代码编写区域&#xf…