16°

OpenGL视角和移动速度随鼠标和滚轮变化

难点理解:

主程序:

#define STB_IMAGE_IMPLEMENTATION
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <STB_IMAGE/stb_image.h>

#include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/type_ptr.hpp> #include <Shader/shader_s.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);

// settings const unsigned int SCR_WIDTH = 800; const unsigned int SCR_HEIGHT = 600; glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 3.0f); glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f); glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f); unsigned int i = 0; float mixValue = 0.2f; float deltaTime = 0.0f; float lastFrame = 0.0f; //鼠标的初始位置 float lastX = 400, lastY = 300; float yaw = -90.0f; // yaw is initialized to -90.0 degrees since a yaw of 0.0 results in a direction vector pointing to the right so we initially rotate a bit to the left. float pitch = 0.0f; bool firstMouse = true; float fov = 45.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); // uncomment this statement to fix compilation on OS X #endif

GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
if (window == NULL)
{
	std::cout &lt;&lt; "Failed to create GLFW window" &lt;&lt; std::endl;
	glfwTerminate();
	return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

// glad: load all OpenGL function pointers
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
	std::cout &lt;&lt; "Failed to initialize GLAD" &lt;&lt; std::endl;
	return -1;
}

//开启Z缓冲,即是深度测试
glEnable(GL_DEPTH_TEST);
// build and compile our shader zprogram
Shader ourShader("6.1.texture.vs", "6.1.texture.fs");


float vertices[] = {
	-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
};

glm::vec3 cubePositions[] = {
	glm::vec3(0.0f,  0.0f,  0.0f),
	glm::vec3(2.0f,  5.0f, -15.0f),
	glm::vec3(-1.5f, -2.2f, -2.5f),
	glm::vec3(-3.8f, -2.0f, -12.3f),
	glm::vec3(2.4f, -0.4f, -3.5f),
	glm::vec3(-1.7f,  3.0f, -7.5f),
	glm::vec3(1.3f, -2.0f, -2.5f),
	glm::vec3(1.5f,  2.0f, -2.5f),
	glm::vec3(1.5f,  0.2f, -1.5f),
	glm::vec3(-1.3f,  1.0f, -1.5f)
};

unsigned int VBO, VAO;
glGenVertexArrays(1, &amp;VAO);
glGenBuffers(1, &amp;VBO);
//glGenBuffers(1, &amp;EBO);

glBindVertexArray(VAO);

glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
//glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

// position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);

// texture coord attribute
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);


//生成纹理
unsigned int texture1, texture2;
glGenTextures(1, &amp;texture1);
glBindTexture(GL_TEXTURE_2D, texture1);

// 为当前绑定的纹理对象设置环绕、过滤方式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
// set texture filtering parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

// load image, create texture and generate mipmaps
int width, height, nrChannels;
//OpenGL要求y轴0.0坐标是在图片的底部的,但是图片的y轴0.0坐标通常在顶部,故需要倒置
//将图片载入生成一个纹理
unsigned char *data1 = stbi_load("F:/C++项目/LibsInclude/src/container.jpg", &amp;width, &amp;height, &amp;nrChannels, 0);
if (data1)
{
//生成纹理
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data1);
//当前绑定的纹理自动生成所有需要的多级渐远纹理
glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
std::cout &lt;&lt; "Failed to load texture" &lt;&lt; std::endl;
}
//释放图像内存
stbi_image_free(data1);


//生成第二个纹理
glGenTextures(1, &amp;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);
data1 = stbi_load("F:/C++项目/LibsInclude/src/face1.jpeg", &amp;width, &amp;height, &amp;nrChannels, 0);
if (data1)
{
//生成纹理
//笑脸图片有a通道glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);//参数设置为GL_RGBA
//第一个参数指定了纹理目标(Target)。设置为GL_TEXTURE_2D意味着会生成与当前绑定的纹理对象在同一个目标上的纹理(任何绑定到GL_TEXTURE_1D和GL_TEXTURE_3D的纹理不会受到影响)。
//第二个参数为纹理指定多级渐远纹理的级别,如果你希望单独手动设置每个多级渐远纹理的级别的话。这里我们填0,也就是基本级别。
//第三个参数告诉OpenGL我们希望把纹理储存为何种格式。我们的图像只有RGB值,因此我们也把纹理储存为RGB值。
//第四个和第五个参数设置最终的纹理的宽度和高度。我们之前加载图像的时候储存了它们,所以我们使用对应的变量。
//下个参数应该总是被设为0(历史遗留的问题)。
//第七第八个参数定义了源图的格式和数据类型。我们使用RGB值加载这个图像,并把它们储存为char(byte)数组,我们将会传入对应值。
//最后一个参数是真正的图像数据。
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data1);
//当前绑定的纹理自动生成所有需要的多级渐远纹理
glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
std::cout &lt;&lt; "Failed to load texture" &lt;&lt; std::endl;
}
//释放图像内存
stbi_image_free(data1);


//将着色器采样器与纹理单元进行联系在一起
//设置每个采样器的方式告诉OpenGL每个着色器采样器属于哪个纹理单元
//在设置uniform1前先激活着色器
ourShader.use();

//设置uniform值
//texture1着色器采样器接受第一个纹理单元(三种表达方式)
//glUniform1i(glGetUniformLocation(ourShader.ID, "texture1"), 0);
//或者
//ourShader.setInt("texture1", 0);
glUniform1i(glGetUniformLocation(ourShader.ID, "texture1"), GL_TEXTURE0 - GL_TEXTURE0);
//texture2着色器采样器接受第二个纹理单元(三种表达方式)
glUniform1i(glGetUniformLocation(ourShader.ID, "texture2"), GL_TEXTURE1 - GL_TEXTURE0);





// 渲染
while (!glfwWindowShouldClose(window))
{
	//注册回调函数
	glfwSetCursorPosCallback(window, mouse_callback);
	glfwSetScrollCallback(window, scroll_callback);
	float currentFrame = glfwGetTime();
	deltaTime = currentFrame - lastFrame;
	lastFrame = currentFrame;
	processInput(window);

	glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
	//每次渲染迭代之前清除深度缓冲,不然会保留上一帧的深度信息
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	i = i + 1;
	//std::cout &lt;&lt; " i= " &lt;&lt; i&lt;&lt; std::endl;

	//在纹理单元的状态下,将采样器绑定
	// bind Texture:会自动把纹理赋值给片段着色器的采样器
	//先激活纹理单元,然后再绑定,若只有一个纹理单元,默认激活状态
	//GL_TEXTURE0:就是一个纹理单元,是按顺序定义的,OpenGL至少保证有16个纹理单元
	//texture1:代表着色器采样器
	glActiveTexture(GL_TEXTURE0);
	//会绑定这个纹理到当前激活的纹理单元,于是就将纹理和纹理单元联系在一起了
	glBindTexture(GL_TEXTURE_2D, texture1);
	glActiveTexture(GL_TEXTURE1);
	glBindTexture(GL_TEXTURE_2D, texture2);


	// activate shader
	ourShader.use();

	//设置两个纹理的混合度
	ourShader.setFloat("mixValue", mixValue);
	//变换
	//定义变换矩阵
	//模型矩阵(Model):位移(translate)  缩放(scale) 旋转(rotate)
	//glm::mat4 model(1.0f);
	//model = glm::rotate(model, (float)glfwGetTime(), glm::vec3(0.5f, 1.0f, 0.0f));
	//观察矩阵(view):绕圆轨迹运行
	float radius = 10.0f;
	float camX = sin(glfwGetTime()) * radius;
	float camZ = cos(glfwGetTime()) * radius;
	glm::mat4 view(1.0f);
	// 注意,我们将矩阵向我们要进行移动场景的反方向移动。
	//todo ??? 为社么是cameraPos + cameraFront
	//cameraFront是方向向量的反方向
	view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);

	//投影矩阵(Projection)
	glm::mat4 projection(1.0f);
	projection = glm::perspective(glm::radians(fov), 800.0f / 600.0f, 0.1f, 100.0f);


	//将矩阵传入着色器
	glUniformMatrix4fv(glGetUniformLocation(ourShader.ID, "view"), 1, GL_FALSE, glm::value_ptr(view));
	glUniformMatrix4fv(glGetUniformLocation(ourShader.ID, "projection"), 1, GL_FALSE, glm::value_ptr(projection));


	glBindVertexArray(VAO);
	for (unsigned int i = 0; i &lt; 10; i++)
	{
		glm::mat4 model(1.0f);
		model = glm::translate(model, cubePositions[i]);
		float angle = 20.0f * (i+1);
		model = glm::rotate(model,  float(glfwGetTime()) * glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f));
		glUniformMatrix4fv(glGetUniformLocation(ourShader.ID, "model"), 1, GL_FALSE, glm::value_ptr(model));

		glDrawArrays(GL_TRIANGLES, 0, 36);
	}

	glfwSwapBuffers(window);
	glfwPollEvents();
}
	glDeleteVertexArrays(1, &amp;VAO);
	glDeleteBuffers(1, &amp;VBO);
	//glDeleteBuffers(1, &amp;EBO);
	glfwTerminate();
	return 0;

}

void processInput(GLFWwindow *window) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) glfwSetWindowShouldClose(window, true);

if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS)
{
	mixValue += 0.001f;
	if (mixValue &gt;= 1.0f)
	mixValue = 1.0f;
}
if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS)
{
	mixValue -= 0.001f; 
	if (mixValue &lt;= 0.0f)
	mixValue = 0.0f;
}

//更改相机的位置
float cameraSpeed = 2.5 * deltaTime; ; // adjust accordingly
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
	cameraPos += cameraSpeed * cameraFront;
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
	cameraPos -= cameraSpeed * cameraFront;
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
	cameraPos -= glm::cross(cameraFront, cameraUp) * cameraSpeed;
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
	cameraPos += glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;

}

void framebuffer_size_callback(GLFWwindow* window, int width, int height) { glViewport(0, 0, width, height); }

//鼠标事件的回调函数 void mouse_callback(GLFWwindow* window, double xpos, double ypos) { //判断鼠标是不是第一次获取输入 if (firstMouse) { lastX = xpos; lastY = ypos; firstMouse = false; }

//在窗口坐标中,y轴是从上往下增加的,
float xoffset = xpos  - lastX;
float yoffset = lastY - ypos ;
lastX = xpos;
lastY = ypos;
std::cout &lt;&lt; "ypos=" &lt;&lt; ypos &lt;&lt; std::endl;

//设置零敏度
float sensitivity = 0.05f;
xoffset *= sensitivity;
yoffset *= sensitivity;

yaw  += xoffset;
pitch += yoffset;
//设置限制
if (pitch &gt; 89.0f)
	pitch = 89.0f;
if (pitch &lt;  -89.0f)
	pitch = -89.0f;

//计算方向向量
glm::vec3 front(1.0f);
front.x = cos(glm::radians(pitch)) * cos(glm::radians(yaw));
front.y = sin(glm::radians(pitch));
front.z = cos(glm::radians(pitch)) * sin(glm::radians(yaw));
cameraFront = glm::normalize(front);

}

//鼠标滚轮改变视角大小 void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) { if (fov >= 1.0f && fov <= 45.0f) fov -= yoffset; if (fov <= 1.0f) fov = 1.0f; if (fov >= 45.0f) fov = 45.0f; }

顶点着色器:

#version 330 core
layout (location = 0) in vec3 aPos;

layout (location = 1) in vec2 aTexCoord;

out vec2 TexCoord;

uniform mat4 model; uniform mat4 view; uniform mat4 projection;

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

片段着色器:

#version 330 core
out vec4 FragColor;

in vec2 TexCoord; uniform float mixValue;

// 采样器:解决了如何将纹理对象传给片段着色器 //纹理单元· uniform sampler2D texture1; uniform sampler2D texture2;

//这个片段着色器的输出就是纹理的(插值)纹理坐标上的(过滤后的)颜色。 void main() { FragColor = mix(texture(texture1, TexCoord), texture(texture2, vec2(TexCoord.x, TexCoord.y)), mixValue);

}

结果:

本文由【黑白双键】发布于开源中国,原文链接:https://my.oschina.net/1024and1314/blog/3136814

全部评论: 0

    我有话说: