C++/OpenGL 入门(15):mipmapps , wrapping and tiling

  1. 来源:《Computer Graphics Programming in OpenGL Using C++ 》by V Scott
    Gordon John L Clevenger
  2. 内容:程序5.1 Pyramid with Brick Texture,书P115-122页,PDF133-141/403

生成

①贴图之外设置背景色(红色)

② 将贴图铺满表面
在这里插入图片描述

在这里插入图片描述② 将贴图铺满表面,每一行中相互镜像,上下行相互颠倒
在这里插入图片描述
③将纹理的边缘的行列颜色延伸,作为四面体的背景色。
在这里插入图片描述

在这里插入图片描述

笔记

mismapping

Mipmapping:解决当纹理图像的像素resolution和四面体表面的像素不一致时,由于间接采样导致的图像出现错误的情况。实际方法是将纹理图案根据RGB三通道分成新图像,不断缩小。可以通过设置 GL_TEXTURE_MIN_FILTER 参数来设置缩小的方法:
GL_NEAREST_MIPMAP_NEAREST : 选择最近的点
GL_LINEAR_MIPMAP_NEAREST : 选择四个像素线性插值
GL_NEAREST_MIPMAP_LINEAR : 选择两个和要被增加纹理的区域的resolution最接近的mipmaps,然后从两个mipmaps中取出对应的坐标,然后线性插值即可
GL_LINEAR_MIPMAP_LINEAR : 选择两个mipmaps,每个分别线性插值,再将这两个结果线性插值
在这里插入图片描述
OpenGL自动建立 mipmaps,通过在 Utils::loadTexture()getTextureObject() 语句之后加以下三句话:

glBindTexture(GL_TEXTURE_2D, textureID); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); 
glGenerateMipmap(GL_TEXTURE_2D);

这就告诉OpenGL去生成mipmaps

Anisotropic filtering

Mipmaps 有时候会使得图像变得很糊,是因为构造mipmaps时候,图像的两个轴的单元会变小。AF方法需要的计算量比较大,能够处理由于mipmaps而变糊的图像,以下代码需要在生成mipmap后加入:

// if mipmapping 
glBindTexture(GL_TEXTURE_2D, textureID); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); 
glGenerateMipmap(GL_TEXTURE_2D); 
// if also anisotropic filtering 
if (glewIsSupported("GL_EXT_texture_filter_anisotropic")) { 
GLfloat anisoSetting = 0.0f; 
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &anisoSetting); 
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisoSetting); }

将纹理图像的坐标设置在0-1范围内,采用 glTexParameteri(), 参数有:
GL_REPEAT:相同纹理重复贴图
GL_MIRRORED_REPEAT : 纹理在同一行贴图时,相邻两个纹理时镜像的
GL_CLAMP_TO_EDGE : 坐标小于0或者大于1的,设置为0或者1
GL_CLAMP_TO_BORDER: 将超过0 – 1 的值设为特定颜色

更改设置获得生成图片三种结果

在”5.2 Utils.cpp“ 文件中,将需要得到结果的对应内容解除注释,其他内容注释不执行
在这里插入图片描述

完整代码

一共有 7 个文件,分别是:
220228 5.2 MipmapTiling.cpp
5.2 Utils.cpp
5.2 Utils.h
5.2 fragShader.glsl
5.2 vertShader.glsl
brick1.jpg (墙面纹理图)
5.2 face.jpg (滑稽坏笑图)

220228 5.2 MipmapTiling.cpp

#include <string>
#include <iostream>
#include <fstream>
#include <cmath>


#include "glm\glm.hpp"
#include "glm\gtc\type_ptr.hpp"
#include "glm\gtc\matrix_transform.hpp"
#include "Utils\5.2 Utils.h"
using namespace std;
#define numVAOs 1
#define numVBOs 2
float cameraX, cameraY, cameraZ;
float pyrLocX, pyrLocY, pyrLocZ;
GLuint renderingProgram;
GLuint vao[numVAOs];
GLuint vbo[numVBOs];
GLuint brickTexture; // 纹理图片ID

// allocate variables used in display() function, 
// so that they won’t need to be allocated during rendering
GLuint mvLoc, projLoc;
int width, height;
float aspect;
glm::mat4 pMat, vMat, mMat, mvMat;

void setupVertices(void) {

	// pyramid with 18 vertices, comprising 6 triangles (four sides, and two on the bottom)
	float pyramidPositions[54] =
	{ -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 0.0f, // front face
		1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 1.0f, 0.0f, // right face
		1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 1.0f, 0.0f, // back face
		-1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 0.0f, // left face
		-1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, // base – left front
		1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f // base – right back
	};
	//设置纹理的顶点对应关系;
	float pyrTexCoords[36] = {
		0.0f, 0.0f, 1.0f*5,		0.0f,		0.5f * 5, 1.0f * 5, 0.0f,		0.0f,		1.0f * 5, 0.0f, 0.5f * 5, 1.0f * 5,// 前面和右面
		0.0f, 0.0f, 1.0f * 5,	0.0f,		0.5f * 5, 1.0f * 5, 0.0f,		0.0f,		1.0f * 5, 0.0f, 0.5f * 5, 1.0f * 5,// 后面和左面
		0.0f, 0.0f, 1.0f * 5,	1.0f * 5,	0.0f,	  1.0f * 5, 1.0f * 5,	1.0f * 5,	0.0f,	  0.0f, 1.0f * 5, 0.0f // 底面的三角形
	};

	glGenVertexArrays(1, vao);
	glBindVertexArray(vao[0]);
	glGenBuffers(numVBOs, vbo);
	// 四面体
	glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
	glBufferData(GL_ARRAY_BUFFER, sizeof(pyramidPositions), pyramidPositions, GL_STATIC_DRAW);
	// 纹理
	glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
	glBufferData(GL_ARRAY_BUFFER, sizeof(pyrTexCoords), pyrTexCoords, GL_STATIC_DRAW);
}
void init(GLFWwindow* window) {


	renderingProgram = createShaderProgram("add/5.2 vertShader.glsl", "add/5.2 fragShader.glsl");
	cameraX = 0.0f; cameraY = 0.0f; cameraZ = 8.0f;
	pyrLocX = 1.0f; pyrLocY = -1.0f; pyrLocZ = 0.0f; // shift down Y to reveal perspective
	setupVertices();
	brickTexture = loadTexture("add/brick1.jpg"); // 加载纹理的图片
}

void display(GLFWwindow* window, double currentTime) {
	glClear(GL_DEPTH_BUFFER_BIT);
	glUseProgram(renderingProgram);
	// get the uniform variables for the MV and projection matrices
	mvLoc = glGetUniformLocation(renderingProgram, "mv_matrix");
	projLoc = glGetUniformLocation(renderingProgram, "proj_matrix");
	// build perspective matrix
	glfwGetFramebufferSize(window, &width, &height);
	aspect = (float)width / (float)height;
	pMat = glm::perspective(1.0472f, aspect, 0.1f, 1000.0f); // 1.0472 radians = 60 degrees
	// build view matrix, model matrix, and model-view matrix
	vMat = glm::translate(glm::mat4(1.0f), glm::vec3(-cameraX, -cameraY, -cameraZ));

	// vbo[0]
	mMat = glm::translate(glm::mat4(1.0f), glm::vec3(pyrLocX, pyrLocY, pyrLocZ));
	mvMat = vMat * mMat;
	// copy perspective and MV matrices to corresponding uniform variables
	glUniformMatrix4fv(mvLoc, 1, GL_FALSE, glm::value_ptr(mvMat));
	glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(pMat));
	// associate VBO with the corresponding vertex attribute in the vertex shader
	glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
	glEnableVertexAttribArray(0);
	// 纹理
	glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
	glEnableVertexAttribArray(1);
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, brickTexture);
	// adjust OpenGL settings and draw model
	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LEQUAL);
	glFrontFace(GL_CCW);// 锥体的三角形是逆时针的面认为是正方向
	glDrawArrays(GL_TRIANGLES, 0, 18);

}

int main(void) { // main() is unchanged from before
	if (!glfwInit()) { exit(EXIT_FAILURE); }
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	GLFWwindow* window = glfwCreateWindow(600, 600, "Chapter 5 - program 2", NULL, NULL);
	glfwMakeContextCurrent(window);
	if (glewInit() != GLEW_OK) { exit(EXIT_FAILURE); }
	glfwSwapInterval(1);
	init(window);
	while (!glfwWindowShouldClose(window)) {
		display(window, glfwGetTime());
		glfwSwapBuffers(window);
		glfwPollEvents();
	}
	glfwDestroyWindow(window);
	glfwTerminate();
	exit(EXIT_SUCCESS);
}

5.2 Utils.cpp

#include "Utils/5.2 Utils.h"
#include "GL/glew.h"
#include "GLFW/glfw3.h"
#include "SOIL2/SOIL2.h"

#include <iostream>
#include <string>
#include <fstream>
using namespace std;


GLuint createShaderProgram(const char* a_Path, const char* b_Path) {
	GLint vertCompiled;
	GLint fragCompiled;
	GLint linked;
	string vertShaderStr = readShaderSource(a_Path); // 文件在add文件夹中
	string fragShaderStr = readShaderSource(b_Path);
	const char *vertShaderSrc = vertShaderStr.c_str();
	const char *fragShaderSrc = fragShaderStr.c_str();
	GLuint vShader = glCreateShader(GL_VERTEX_SHADER);
	GLuint fShader = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(vShader, 1, &vertShaderSrc, NULL);
	glShaderSource(fShader, 1, &fragShaderSrc, NULL);
	// 在编译着色器时,捕捉错误
	glCompileShader(vShader);
	checkOpenGLError();
	glGetShaderiv(vShader, GL_COMPILE_STATUS, &vertCompiled);
	if (vertCompiled != 1) {
		cout << "vertex compilation failed" << endl;
		printShaderLog(vShader);
	}
	glCompileShader(fShader);
	checkOpenGLError();
	glGetShaderiv(fShader, GL_COMPILE_STATUS, &fragCompiled);
	if (fragCompiled != 1) {
		cout << "fragment compilation failed" << endl;
		printShaderLog(fShader);
	}
	GLuint vfProgram = glCreateProgram();
	glAttachShader(vfProgram, vShader);
	glAttachShader(vfProgram, fShader);
	glLinkProgram(vfProgram);
	checkOpenGLError();
	glGetProgramiv(vfProgram, GL_LINK_STATUS, &linked);
	if (linked != 1) {
		cout << "linking failed" << endl;
		printProgramLog(vfProgram);
	}

	return vfProgram;
}

string readShaderSource(const char *filePath) {
	string content;
	ifstream fileStream(filePath, ios::in);
	string line = "";
	while (!fileStream.eof()) {
		getline(fileStream, line);
		content.append(line + "\n");
	}
	fileStream.close();
	return content;
}
bool checkOpenGLError() {
	bool foundError = false;
	int glErr = glGetError();
	while (glErr != GL_NO_ERROR) {
		cout << "glError: " << glErr << endl;
		foundError = true;
		glErr = glGetError();
	}
	return foundError;
}

void printProgramLog(int prog) {
	int len = 0;
	int chWrittn = 0;
	char *log;
	glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &len);
	if (len > 0) {
		log = (char *)malloc(len);
		glGetProgramInfoLog(prog, len, &chWrittn, log);
		cout << "Program Info Log: " << log << endl;
		free(log);
	}
}
void printShaderLog(GLuint shader) {
	int len = 0;
	int chWrittn = 0;
	char *log;
	glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len);
	if (len > 0) {
		log = (char *)malloc(len);
		glGetShaderInfoLog(shader, len, &chWrittn, log);
		cout << "Shader Info Log: " << log << endl;
		free(log);
	}
}

GLuint loadTexture(const char *texImagePath) {
	GLuint textureID;
	textureID = SOIL_load_OGL_texture(texImagePath,
		SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_INVERT_Y);
	if (textureID == 0) cout << "could not find texture file" << texImagePath << endl;
	
	// mipmaps
	glBindTexture(GL_TEXTURE_2D, textureID);

	 不倒置也不镜像——多选一
	//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_WRAP_S, GL_MIRRORED_REPEAT);
	//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);

	 仅有一个,其余颜色为红色——多选一
	//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
	//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
	//float redColor[4] = { 1.0f, 0.0f, 0.0f, 1.0f };
	//glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, redColor);

	// 仅有一个,其余为图片最边缘一行一列的颜色拓展——多选一
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

	glGenerateMipmap(GL_TEXTURE_2D);
	
	// if also anisotropic filtering 
	if (glewIsSupported("GL_EXT_texture_filter_anisotropic")) {
		GLfloat anisoSetting = 0.0f;
		glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &anisoSetting);
		//glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisoSetting);
	}

	return textureID;
}

5.2 Utils.h

#pragma once
#ifndef UTILS_H
#define UTILS_H
#include <string>
#include "GL\glew.h"
#include "GLFW\glfw3.h"
using namespace std;

GLuint createShaderProgram(const char* a_Path, const char* b_Path);
string readShaderSource(const char *filePath);
bool checkOpenGLError();
void printProgramLog(int prog);
void printShaderLog(GLuint shader);
GLuint loadTexture(const char *texImagePath);


#endif // !UTILS_H


5.2 fragShader.glsl

#version 430
in vec2 tc; // interpolated incoming texture coordinate
out vec4 color;
uniform mat4 mv_matrix;
uniform mat4 proj_matrix;
layout (binding=0) uniform sampler2D samp;
void main(void)
{ color = texture(samp, tc);
}

5.2 vertShader.glsl

#version 430
layout (location=0) in vec3 pos;
layout (location=1) in vec2 texCoord;
out vec2 tc; // texture coordinate output to rasterizer for interpolation
uniform mat4 mv_matrix;
uniform mat4 proj_matrix;
layout (binding=0) uniform sampler2D samp; // not used in vertex shader 
void main(void)
{	 gl_Position = proj_matrix * mv_matrix * vec4(pos,1.0);
	tc = texCoord;
}

brick1.jpg (墙面纹理图)

在这里插入图片描述

5.2 face.jpg (滑稽坏笑图)

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值