一,基础概念

对绘制的图形进行位置,旋转,缩放变化实现整个界面的变换,主要通过各种变换矩阵实现(具体资料参考教程链接或者线性代数);

二,实现基础变换

由于OpenGL没有自带任何的矩阵和向量相关的函数,需要自己实现相关功能或者下载数学库,本教程使用的是外部下载的GLM库;

1,下载GLM数学库

  • 下载链接;https://link.zhihu.com/?target=https%3A///g-truc/glm/tags

  • 下载glm文件,解压找到里边glm文件夹拷贝到环境搭建时的include文件夹内;

ue4 opencv Android链接文件_opengl画旋转的正方形

目录

  • 使用前包含相关头文件,我们需要的GLM的大多数功能都可以从下面这3个头文件中找到;
#include 
#include 
#include

2,测试一下GLM是否正常工作

glm::vec4 vec(1.0f, 0.0f, 0.0f, 1.0f);
// 如果使用的是0.9.9及以上版本
// 下面这行代码就需要改为:
// glm::mat4 trans = glm::mat4(1.0f)
glm::mat4 trans;
trans = glm::translate(trans, glm::vec3(1.0f, 1.0f, 0.0f));
vec = trans * vec;
std::cout << vec.x << vec.y << vec.z << std::endl;
//如若工作正常 这个代码片段将会输出210

3,具体实现代码



ue4 opencv Android链接文件_数据_02

ue4 opencv Android链接文件_数据_03

实现效果

更改渲染逻辑(LearnOpenGL.cpp文件)

//GLAD的头文件包含了正确的OpenGL头文件(例如GL/gl.h),所以需要在其它依赖于OpenGL的头文件之前包含GLAD。
#include 
#include 
//GLM数学库
#include 
#include 
#include 
#include "ShaderBase.h"          //基础的渲染着色器
 //通过定义STB_IMAGE_IMPLEMENTATION,预处理器会修改头文件,让其只包含相关的函数定义源码,等于是将这个头文件变为一个 .cpp 文件了
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"         //图片处理
#include 
using namespace std;
/*******************************************定义常量************************************************/
//设置窗口的宽和高
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
float mixValue = 0.2f;
/*******************************************函数************************************************/
//响应键盘输入事件
void processInput(GLFWwindow* window)
{
	//ESC 退出窗口
	//glfwGetKey()用来判断一个键是否按下。第一个参数是GLFW窗口句柄,第二个参数是一个GLFW常量,代表一个键。
	//GLFW_KEY_ESCAPE表示Esc键。如果Esc键按下了,glfwGetKey将返回GLFW_PRESS(值为1),否则返回GLFW_RELEASE(值为0)。
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
	{
		//glfwSetWindowShouldClose()函数,为窗口设置关闭标志。第一个参数是窗口句柄,第二个参数表示是否关闭
		//这里为GLFW_TRUE,表示关闭该窗口。
		//注意,这时窗口不会立即被关闭,但是glfwWindowShouldClose()将返回GLFW_TRUE,到了glfwTerminate()就会关闭窗口。
		glfwSetWindowShouldClose(window, true);
	}
	//上键
	if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS)
	{
		mixValue += 0.01f;
		if (mixValue >= 1.0f)
			mixValue = 1.0f;
	}
	//下键
	if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS)
	{
		mixValue -= 0.01f;
		if (mixValue <= 0.0f)
			mixValue = 0.0f;
	}
}
//当用户改变窗口的大小的时候,视口也应该被调整。
//对窗口注册一个回调函数(Callback Function),它会在每次窗口大小被调整的时候被调用
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
	//OpenGL渲染窗口的尺寸大小
	//glViewport函数前两个参数控制窗口左下角的位置。第三个和第四个参数控制渲染窗口的宽度和高度(像素)
	glViewport(0, 0, width, height);
}
/*******************************************主函数************************************************/
//主函数
int main()
{
	//测试代码
	//glm::vec4 vec(1.0f, 0.0f, 0.0f, 1.0f);
	//glm::mat4 trans = glm::mat4(1.0f);
	//trans = glm::translate(trans, glm::vec3(1.0f, 1.0f, 0.0f));
	//vec = trans * vec;
	//std::cout << vec.x << vec.y << vec.z << std::endl;
	//初始化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(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", nullptr, nullptr);
	if (window == nullptr)
	{
		cout << "Failed to create GLFW window" << endl;
		glfwTerminate();
		return -1;
	}
	//创建完毕之后,需要让当前窗口的环境在当前线程上成为当前环境,就是接下来的画图都会画在我们刚刚创建的窗口上
	glfwMakeContextCurrent(window);
	//告诉GLFW我们希望每当窗口调整大小的时候调用这个函数
	glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
	//glad寻找opengl的函数地址,调用opengl的函数前需要初始化glad
	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
	{
		std::cout << "Failed to initialize GLAD" << std::endl;
		return -1;
	}
	/*******************************************着色器************************************************/
	//构建和编译Shader
	Shader ourShader01("vs01.vs", "fs01.fs");
	Shader ourShader02("vs02.vs", "fs02.fs");
	/*******************************************顶点数据************************************************/
	//设置顶点数据和顶点属性
	//第一个三角形数据
	float vertices01[] = {
		// 位置              顶点颜色              UV
		0.1f, 0.9f, 0.0f,    1.0f,0.0f,0.0f,       0.0f,1.0f,
		0.9f, 0.9f, 0.0f,    0.0f,1.0f,0.0f,       1.0f,1.0f,
		0.9f, 0.1f, 0.0f,    0.0f,0.0f,1.0f,       1.0f,0.0f,
		0.1f, 0.1f, 0.0f,    1.0f,1.0f,1.0f,       0.0f,0.0f
	};
	unsigned int indices[] = {
	   0, 1, 3,
	   1, 2, 3
	};
	// 第二个三角形数据
	float vertices02[] = {
		//位置                                  UV
		-0.5f, 0.9f, 0.0f,                   0.5f,1.0f,
		-0.1f, 0.1f, 0.0f,                   1.0f,0.0f,
		-0.9f, 0.1f, 0.0f,                   0.0f,0.0f
	};
	/*******************************************VAO/VBO/EBO************************************************/
	//创建 VBO 顶点缓冲对象 VAO顶点数组对象 EBO索引缓冲对象
	unsigned int VBOs[2], VAOs[2], EBOs[2];
	glGenVertexArrays(2, VAOs);
	glGenBuffers(2, VBOs);
	glGenBuffers(2, EBOs);
	//绑定VAO,VBO与EBO对象
	/*******************************************第一个************************************************/
	glBindVertexArray(VAOs[0]);
	glBindBuffer(GL_ARRAY_BUFFER, VBOs[0]);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBOs[0]);
	// 复制顶点数据到缓冲内存中
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices01), vertices01, GL_STATIC_DRAW);
	//赋值顶点索引到缓冲内存中
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
	//链接顶点属性,设置顶点属性指针
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(0);
	//顶点颜色
	//属性位置值为1的顶点属性
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
	//以顶点属性位置值作为参数,启用顶点属性;顶点属性默认是禁用的。
	glEnableVertexAttribArray(1);
	//顶点UV坐标
	glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
	glEnableVertexAttribArray(2);
	/*******************************************第二个************************************************/
	//绑定VAO,VBO与EBO对象
	glBindVertexArray(VAOs[1]);
	glBindBuffer(GL_ARRAY_BUFFER, VBOs[1]);
	//复制顶点数据到缓冲内存中
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices02), vertices02, GL_STATIC_DRAW);
	//链接顶点属性,设置顶点属性指针
	//顶点位置
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
	//以顶点属性位置值作为参数,启用顶点属性;顶点属性默认是禁用的。
	glEnableVertexAttribArray(0);
	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
	glEnableVertexAttribArray(1);
	/*******************************************纹理对象************************************************/
	//生成纹理
	//创建ID
	unsigned int texture1, texture2, texture3;
	/*******************************************第一个纹理对象************************************************/
	//创建纹理对象
	//glGenTextures函数首先需要输入生成纹理的数量,然后把它们储存在第二个参数的unsigned int数组中
	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_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	//声明变量 用来储存图片的宽度,高度和颜色通道个数
	int width, height, nrChannels;
	//因为OpenGL要求y轴0.0坐标是在图片的底部的,但是图片的y轴0.0坐标通常在顶部
	//翻转y轴
	stbi_set_flip_vertically_on_load(true);
	//stbi_load()函数 载入图片数据
	unsigned char *data = stbi_load(("resources/textures/container.jpg"), &width, &height, &nrChannels, 0);
	//判断数据是否加载成功
	if (data)
	{
		//利用载入图片数据,生成纹理
		//当前绑定的纹理对象就会被附加上纹理图像
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
		//为当前绑定的纹理自动生成所有需要的Mipmap(多级渐远纹理)
		glGenerateMipmap(GL_TEXTURE_2D);
	}
	else
	{
		std::cout << "Failed to load texture" << std::endl;
	}
	//删除加载的图片数据,释放内存
	stbi_image_free(data);
	/*******************************************第二个纹理对象************************************************/
	//创建纹理对象
	//glGenTextures函数首先需要输入生成纹理的数量,然后把它们储存在第二个参数的unsigned int数组中
	glGenTextures(1, &texture2);
	//绑定纹理
	glBindTexture(GL_TEXTURE_2D, texture2);
	//设置纹理的环绕方式
	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);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	//声明变量 用来储存图片的宽度,高度和颜色通道个数
	data = stbi_load(("resources/textures/awesomeface.png"), &width, &height, &nrChannels, 0);
	//判断数据是否加载成功
	if (data)
	{
		//利用载入图片数据,生成纹理
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
		//为当前绑定的纹理自动生成所有需要的Mipmap(多级渐远纹理)
		glGenerateMipmap(GL_TEXTURE_2D);
	}
	else
	{
		std::cout << "Failed to load texture" << std::endl;
	}
	//删除加载的图片数据,释放内存
	stbi_image_free(data);
	/* ****************************************第二个三角形******************************************************/
	//glGenTextures函数首先需要输入生成纹理的数量,然后把它们储存在第二个参数的unsigned int数组中
	glGenTextures(1, &texture3);
	//绑定纹理
	glBindTexture(GL_TEXTURE_2D, texture3);
	//设置纹理的环绕方式
	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);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	//因为OpenGL要求y轴0.0坐标是在图片的底部的,但是图片的y轴0.0坐标通常在顶部
	//翻转y轴
	stbi_set_flip_vertically_on_load(true);
	//stbi_load()函数 载入图片数据
	data = stbi_load(("resources/textures/wall.jpg"), &width, &height, &nrChannels, 0);
	//判断数据是否加载成功
	if (data)
	{
		//利用载入图片数据,生成纹理
		//当前绑定的纹理对象就会被附加上纹理图像
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
		//为当前绑定的纹理自动生成所有需要的Mipmap(多级渐远纹理)
		glGenerateMipmap(GL_TEXTURE_2D);
	}
	else
	{
		std::cout << "Failed to load texture" << std::endl;
	}
	//删除加载的图片数据,释放内存
	stbi_image_free(data);
	/*******************************************分配纹理单元************************************************/
	//设置uniform前,激活着色器
	ourShader01.use();
	//glUniform1i设置每个采样器的方式告诉OpenGL每个着色器采样器属于哪个纹理单元。
	//只需要设置一次即可,所以这个会放在渲染循环的前面
	//手动设置
	//glUniform1i(glGetUniformLocation(ourShader01.ID, "texture1"), 0);
	//使用内置自定义函数
	ourShader01.setInt("texture1", 0);
	ourShader01.setInt("texture2", 1);
	/*******************************************第二个三角形************************************************/
	ourShader02.use();
	ourShader02.setInt("texture3", 2);
	/*******************************************渲染循环************************************************/
	//程序可以一直运行,直到用户关闭窗口。这样我们就需要创建一个循环,叫做游戏循环
	//glfwWindowShouldClose()检查窗口是否需要关闭。如果是,游戏循环就结束了,接下来我们将会清理资源,结束程序
	while (!glfwWindowShouldClose(window))
	{
		//响应键盘输入
		processInput(window);
		//设置清除颜色
		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		//清除当前窗口,把颜色设置为清除颜色
		glClear(GL_COLOR_BUFFER_BIT);
		/*******************************************绘制************************************************/
		//获取时间
		float timeValue = glfwGetTime();
		float greenValue = sin(timeValue) / 2.0f + 0.5f;
		//激活链接程序,激活着色器,开始渲染
		//绘制第一个三角形
		//在绑定纹理之前先激活纹理单元
		glActiveTexture(GL_TEXTURE0);
		//glBindTexture()函数调用,会绑定这个纹理到当前激活的纹理单元
		//纹理单元GL_TEXTURE0默认总是被激活
		glBindTexture(GL_TEXTURE_2D, texture1);
		glActiveTexture(GL_TEXTURE1);
		glBindTexture(GL_TEXTURE_2D, texture2);
		ourShader01.use();
		ourShader01.setFloat("YOffset", greenValue);
		ourShader01.setFloat("mixValue", mixValue);
		//创建一个矩阵4X4
		glm::mat4 transform = glm::mat4(1.0f);
		//移动 旋转和缩放矩阵
		transform = glm::translate(transform, glm::vec3(0.5f, 0.0f, 0.0f));
		transform = glm::scale(transform, glm::vec3(0.5, 0.5, 0.5));
		transform = glm::rotate(transform, (float)glfwGetTime(), glm::vec3(0.0f, 0.0f, 1.0f));
		//为着色器中的矩阵赋值
		unsigned int transformLoc01 = glGetUniformLocation(ourShader01.ID, "transform01");
		glUniformMatrix4fv(transformLoc01, 1, GL_FALSE, glm::value_ptr(transform));
		//绑定VAO
		glBindVertexArray(VAOs[0]);
		//绘制四边形
		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
		//绘制三角形 三个顶点
		//glDrawArrays(GL_TRIANGLES, 0, 3);
		//绘制第二个
		//在绑定纹理之前先激活纹理单元
		glActiveTexture(GL_TEXTURE2);
		glBindTexture(GL_TEXTURE_2D, texture3);
		ourShader02.use();
		ourShader02.setVec4("outColor", 0.0f,greenValue,0.0f,1.0f);
		//创建一个矩阵4X4
		glm::mat4 transform02 = glm::mat4(1.0f);
		//移动 旋转和缩放矩阵
		transform02 = glm::scale(transform02, glm::vec3(greenValue, greenValue, greenValue));
		//为着色器中的矩阵赋值
		unsigned int transformLoc02 = glGetUniformLocation(ourShader02.ID, "transform02");
		glUniformMatrix4fv(transformLoc02, 1, GL_FALSE, glm::value_ptr(transform02));
		//绑定VAO
		glBindVertexArray(VAOs[1]);
		//绘制三角形
		glDrawArrays(GL_TRIANGLES, 0, 3);
		/*******************************************结束************************************************/
		//交换颜色缓冲
		glfwSwapBuffers(window);
		//处理事件
		glfwPollEvents();
	}
	//解除绑定
	glDeleteVertexArrays(2, VAOs);
	glDeleteBuffers(2, VBOs);
	glDeleteBuffers(2, EBOs);
	//释放前面所申请的资源
	glfwTerminate();
	return 0;
}

vs01.vs代码为

#version 330 core
layout (location = 0) in vec3 aPos;             //顶点位置
layout (location = 1) in vec3 aColor;           //顶点颜色
layout (location = 2) in vec2 aTexCoord;        //顶点的UV坐标

out vec3 ourColor;                              //输出颜色
out vec2 TexCoord;                              //输出顶点UV坐标
//out vec3 ourPosition;
uniform float YOffset;                          //声明一个float 变量
uniform mat4 transform01;                      //声明一个矩阵

void main()
{
    //赋值
    gl_Position = transform01*vec4(aPos.x, aPos.y - YOffset, aPos.z, 1.0);
    ourColor = aColor;
    TexCoord = vec2(aTexCoord.x, aTexCoord.y);


}

fs01.fs代码为

#version 330 core
out vec4 FragColor;

in vec3 ourColor;
in vec2 TexCoord;
//in vec3 ourPosition;

uniform sampler2D texture1; //声明一个贴图
uniform sampler2D texture2; //声明一个贴图
uniform float mixValue; //声明控制混合的变量

void main()
{
    //采样贴图
    //mix()函数 接受两个值作为参数,并对它们根据第三个参数进行线性插值
    FragColor = mix(texture(texture1, TexCoord) * vec4(ourColor, 1.0), texture(texture2, vec2(TexCoord.x, TexCoord.y)), mixValue);
}

vs02.vs代码为

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord; //顶点的UV坐标

out vec3 ourPosition;
out vec2 TexCoord; //输出顶点UV坐标
uniform mat4 transform02; //声明一个矩阵

void main()
{
    gl_Position = transform02 * vec4(aPos, 1.0);
    TexCoord = vec2(aTexCoord.x, aTexCoord.y);
    ourPosition = aPos;
}

fs02.fs代码为

#version 330 core
out vec4 FragColor;

in vec3 ourPosition;
in vec2 TexCoord;
uniform vec4 outColor;
uniform sampler2D texture3; //声明一个贴图

void main()
{
    vec4 tex = texture(texture3, TexCoord);
    FragColor = tex * (outColor + vec4(ourPosition, 1.0f));
}



ue4 opencv Android链接文件_opengl画旋转的正方形_04