LearningOpenGL学习总结Day04

纹理(Texture)

用大量的顶点来指定大量的颜色来丰富图像会造成巨大的开销,因此可以使用纹理来解决,纹理是一种2D图片,它可以为物体添加更多的细节。

纹理的环绕方式(Wrap)

因为纹理坐标的范围是(0,0)~(1,1)。如果一个图形的纹理采样在这个坐标的范围之外,那么OpenGL提供了四种方式来处理这种情况:

  • GL_REPEAT:重复纹理图像(默认行为)
  • GL_MIRRORED_REPEAT:也是重复纹理图像,但会以原纹理图的镜像模式重复
  • GL_CLAMP_TO_EDGE:超出的部分会延续纹理的边缘,产生一种拉伸的效果
    (这种环绕方式经常在距离观察者较远的时候用于消除边缘产生的较为不真实的边)
  • GL_CLAMP_TO_BORDER:超出坐标的部分为用户指定的颜色

使用glTexParameter···函数可以单独对每一个坐标轴进行设置(s、t、(如果是3D纹理则还有r))。
例:

glTexParameter(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);

纹理过滤(Filter)

当将分辨率较低的纹理图像放到一个较大的物体上时,需要使用纹理过滤,不同的纹理过滤方式就是告诉OpenGL如何将纹理像素映射到纹理坐标。
纹理过滤最重要的两个方式:

  • GL_NEAREST:邻近过滤
    这种过滤方式,OpenGL会选择中心点距离纹理坐标最近的像素。这也是默认方式。
  • GL_LINEAR:线性过滤
    这种过滤方式,OpenGL会基于纹理坐标附近的像素,计算出一个插值,近似出这些纹理像素之间的颜色,那么中心点距离纹理坐标越近,那么对于最终的样本颜色的贡献越大。
    LearningOpenGL学习总结Day04_第1张图片

由于两种方式的不同,邻近过滤会产生颗粒状的效果,而线性过滤能够产生更为平滑的图案,所以一般在放大(magnify)缩小(minify)时,设置不同的纹理方式能够让图像有更好的表现:

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

多级渐远纹理(Mipmap)

当一个物体距离观察者很远的时候,它只会产生很少的片段,解析度并不高。如果此时仍然保持高分辨率的纹理采样,那么可能会产生不真实的效果并且存在不必要的内存额外开销。因此OpenGL使用多级渐远纹理来处理这种情况,后一个纹理图像是前一个的二分之一,以此类推,不同距离对应着不同的纹理效果。
OpenGL使用glGenerateMipmaps函数创建多级渐远纹理。

为了指定不同的多级渐远纹理级别之间的过滤方式,可以使用四种选项中的一个代替原有的过滤方式:

  • GL_NEAREST_MIPMAP_NEAREST
    使用最邻近的多级渐远纹理来匹配像素大小,并使用邻近插值进行纹理采样
  • GL_LINEAR_MIPMAP_NEAREST
    使用最邻近的多级渐远纹理级别,并使用线性插值进行采样
  • GL_NEAREST_MIPMAP_LINEAR
    在两个最匹配像素大小的多级渐远纹理之间进行线性插值,使用邻近插值进行采样
  • GL_LINEAR_MIPMAP_LINEAR
    在两个邻近的多级渐远纹理之间使用线性插值,并使用线性插值进行采样

并且这些过滤方式只有在缩小操作的时候才有用,因为多级渐远纹理主要就是在纹理被缩小时使用的,纹理放大的时候不会使用多级渐远纹理,而是使用前一小节的普通纹理过滤方式。(为放大过滤设置多级渐远纹理的选项会产生一个GL_INVALID_ENUM错误代码)

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

课后题最后一题:能够改变两个不同纹理的能见度(并且能够上下左右移动物体)

#include 

#define GLEW_STATIC
#include 
#include
#include "./shader/Shader.h"
#include 
void processInput(GLFWwindow*);		//键盘或鼠标的输入
float mix_vertical_offset = 0.0f;
float mix_level_offset = 0.0f;
float mix_visibility = 0.2f;
int main() {
	
#pragma region Init
	//初始化glfw
	glfwInit();
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

	//创建窗口
	GLFWwindow* window = glfwCreateWindow(800, 600, "Learning OpenGL", nullptr, nullptr);
	if (window == nullptr) {
		std::cout << "Create window failed." << std::endl;
		glfwTerminate();
		return -1;
	}
	glfwMakeContextCurrent(window);

	//初始化glew
	glewExperimental = true;
	if (glewInit() != GLEW_OK) {
		std::cout << "Init glew failed." << std::endl;
		glfwTerminate();
		return -1;
	}

	glViewport(0, 0, 800, 600);

	/*glEnable(GL_CULL_FACE);
	glCullFace(GL_BACK);*/
#pragma endregion

#pragma region Shader
	Shader* shader = new Shader("resource/vertexShader.vert", "resource/fragmentShader.frag");

#pragma endregion

	float vertex_data[] = {
		// positions          // colors           // texture coords
		 0.5f,  0.5f, 0.0f,   1.0f, 0.0f, 0.0f,   1.0f, 1.0f, // top right
		 0.5f, -0.5f, 0.0f,   0.0f, 1.0f, 0.0f,   1.0f, 0.0f, // bottom right
		-0.5f, -0.5f, 0.0f,   0.0f, 0.0f, 1.0f,   0.0f, 0.0f, // bottom left
		-0.5f,  0.5f, 0.0f,   1.0f, 1.0f, 0.0f,   0.0f, 1.0f  // top left 
	};
	unsigned int vertex_index[] = {
		0, 1, 3, // first triangle
		1, 2, 3  // second triangle
	};

	

	unsigned int VAO;

	glGenVertexArrays(1, &VAO);
	glBindVertexArray(VAO);

	unsigned int VBO;
	glGenBuffers(1, &VBO);		//生成一个VBO
	glBindBuffer(GL_ARRAY_BUFFER, VBO);		//将VBO绑定到GL_ARRAY_BUFFER
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW);	//将顶点数据填充进缓冲区
	
	unsigned int EBO;
	glGenBuffers(1, &EBO);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(vertex_index), vertex_index, GL_STATIC_DRAW);


	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);	//告诉OpenGL该如何具体地使用这些数据
	glEnableVertexAttribArray(0);	//开启location = 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 texture1, texture2;
	glGenTextures(1, &texture1);
	glBindTexture(GL_TEXTURE_2D, texture1);

	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_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

	
	int width = 0, height, nrChannels;
	stbi_set_flip_vertically_on_load(true);
	unsigned char* data = stbi_load("resource/container.jpg", &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);
	}
	else {
		std::cout << "Failed to load texture" << std::endl;
	}
	stbi_image_free(data);

	glGenTextures(1, &texture2);
	glBindTexture(GL_TEXTURE_2D, texture2);
	// set the texture wrapping parameters
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);	// set texture wrapping to GL_REPEAT (default wrapping method)
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	// set texture filtering parameters
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	// load image, create texture and generate mipmaps
	data = stbi_load("resource/awesomeface.png", &width, &height, &nrChannels, 0);
	if (data)
	{
		// note that the awesomeface.png has transparency and thus an alpha channel, so make sure to tell OpenGL the data type is of GL_RGBA
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
		glGenerateMipmap(GL_TEXTURE_2D);
	}
	else
	{
		std::cout << "Failed to load texture" << std::endl;
	}
	stbi_image_free(data);



		
	shader->use();

	//glUniform1i(glGetUniformLocation(shader->m_ID, "texture1"), 0);
	// or set it via the texture class
	shader->setInt("texture1", 0);
	shader->setInt("texture2", 1);
	//render loop
	while (!glfwWindowShouldClose(window)) {
		//input
		processInput(window);

		//rendering
		glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);
		//glDrawArrays(GL_TRIANGLES, 0, 3);
		glActiveTexture(GL_TEXTURE0);		//激活纹理采样器0 (texture1)
		glBindTexture(GL_TEXTURE_2D, texture1);
		glActiveTexture(GL_TEXTURE1);		//激活纹理采样器1 (texture2)
		glBindTexture(GL_TEXTURE_2D, texture2);
		glBindVertexArray(VAO);
		shader->setFloat("visibility", mix_visibility);
		shader->setFloat("level_offset", mix_level_offset);
		shader->setFloat("vertical_offset", mix_vertical_offset);
		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
		//check and call events and swap the buffers
		glfwSwapBuffers(window);	//swap double buffer(双缓冲)
		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);		//按下ESC 将窗口关闭
	}

	if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS) {
		mix_visibility += 0.001f;
		if (mix_visibility >= 1.0f) mix_visibility = 1.0f;
	}

	if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS) {
		mix_visibility -= 0.001f;
		if (mix_visibility <= 0.0f) mix_visibility = 0.0f;
	}

	if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) {
		mix_vertical_offset += 0.05f;
		if (mix_vertical_offset >= 1.0f) mix_vertical_offset = 1.0f;
	}

	if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) {
		mix_vertical_offset -= 0.05f;
		if (mix_vertical_offset <= -1.0f) mix_vertical_offset = -1.0f;
	}

	if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) {
		mix_level_offset -= 0.05f;
		if (mix_level_offset <= -1.0f) mix_level_offset = -1.0f;
	}

	if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) {
		mix_level_offset += 0.05f;
		if (mix_level_offset >= 1.0f) mix_level_offset = 1.0f;
	}
}

你可能感兴趣的:(笔记,图形渲染)