变换

网友投稿 540 2022-09-01

变换

变换

更多还是矩阵向量的基础内容:

向量:方向和小大。 点积: 只定义了两个向量的夹角。你也许记得90度的余弦值是0,0度的余弦值是1。使用点乘可以很容易测试两个向量是否正交(Orthogonal)或平行。 叉乘: 它需要两个不平行向量作为输入,生成一个正交于两个输入向量的第三个向量。如果输入的两个向量也是正交的,那么叉乘之后将会产生3个互相正交的向量。

缩放:

矩阵的组合:

改着色器,添加变化矩阵,用到uniform

// GLEW#define GLEW_STATIC#include // GLFW#include #include #include "Shader.h"#include #include #include #include void key_callback(GLFWwindow* windows, int key, int scancode, int action, int mode);//顶点着色器源码:const GLuint WIDTH = 800, HEIGHT = 600;float Offset = 0.1;int main(){ /* //此部分写变换 glm::vec4 vec(1.0f, 0.0f, 0.0f, 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; */ //然后是旋转和缩放箱子 glm::mat4 trans; trans = glm::rotate(trans, glm::radians(90.0f), glm::vec3(0.0, 0.0, 1.0)); trans = glm::scale(trans, glm::vec3(0.5, 0.5, 0.5)); //因为我们把这个矩阵传递给了GLM的每个函数,GLM会自动将矩阵相乘 //返回的结果是一个包括了多个变换的变换矩阵。 //转换弧度glm::radians(90.0f)将角度转换为弧度。 std::cout << "Starting GLFW context, OpenGL 3.3" << std::endl; //这都是初始化GLFW,后面的要看文档 glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); //创建窗口, GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr); if (window == nullptr) { std::cout << "Failed to create GLFW window" << std::endl; glfwTerminate(); return -1; } glfwMakeContextCurrent(window);//通知GLFW将我们窗口的上下文设置为当前线程的主上下文 //不知道回调函数为什么要加在这里?? //glfwSetKeyCallback(window, key_callback2);回调函数只有最下面那个有作用 glfwSetKeyCallback(window, key_callback); //初始化GLEW(管理OpenGL的函数指针) glewExperimental = GL_TRUE; if (glewInit() != GLEW_OK) { std::cout << "Failed to initialize GLEW" << std::endl; return -1; } glViewport(0, 0, WIDTH, HEIGHT);//前两个控制左下角的位置,后面是窗口宽度高度(像素) Shader ourShader("shader.vs", "shader.frag"); GLfloat vertices[] = { //位置 //颜色 //----位置---- ----颜色---- - 纹理坐标 - 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // 右上 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // 右下 -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // 左下 -0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // 左上 }; GLuint indices[] = { // Note that we start from 0! 0, 1, 3, // First Triangle 1, 2, 3 // Second Triangle }; GLuint VBO, VAO,EBO; //使用glGenBuffers函数和一个缓冲ID生成一个VBO对象?? glGenBuffers(1, &VBO); glGenVertexArrays(1, &VAO); glGenBuffers(1, &EBO); //绑定VAO glBindVertexArray(VAO); //复制顶点数组到缓冲中,glBufferData是一个专门用来把用户定义的数据复制到当前绑定缓冲的函数 glBindBuffer(GL_ARRAY_BUFFER, VBO);//glBindBuffer函数把新创建的缓冲绑定到GL_ARRAY_BUFFER目标上 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); //设置顶点属性指针,和颜色属性 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0); glEnableVertexAttribArray(0); //因为现在是两个属性,需要向右移动步长,6个 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); glEnableVertexAttribArray(1); //由于我们添加了额外的顶点属性,我们要告诉OPenGL新的顶点格式。 glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat))); glEnableVertexAttribArray(2); glBindVertexArray(0); //安全? //生成纹理 GLuint texture1,texture2; glGenTextures(1, &texture1);//?? //glGenTextures(1, &texture2); //glGenTextures函数首先需要输入生成纹理的数量,然后储存在GLuint数组中,让之前任何纹理指令都可以配置当前绑定的纹理。 //下面这一句是绑定纹理。 //glActiveTexture(GL_TEXTURE0);//多个位置时,使用前需要先激活 glBindTexture(GL_TEXTURE_2D, texture1); //glUniform1i(glGetUniformLocation(ourShader.Program, "ourTexture1"), 0); //同理设置第二个纹理位置 //glActiveTexture(GL_TEXTURE1);//多个位置时,使用前需要先激活 //glBindTexture(GL_TEXTURE_2D, texture2); //glUniform1i(glGetUniformLocation(ourShader.Program, "ourTexture2"), 1); //设置到两个轴上 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); // Set texture wrapping to GL_REPEAT (usually basic wrapping method) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); //上面两句是对S和T轴设置环绕方式,环绕方式为重复纹理图像。 float borderColor[] = { 1.0f, 1.0f, 0.0f, 1.0f }; glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); //下面生成纹理。2D纹理,因此纹理目标是GL_TEXTURE_2D //下面两句设置方法和缩小的纹理过滤方式 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); //使用SOIL加载图片,自此到循环前都是加载并生成纹理。 int width, height; std::cout << SOIL_last_result() << std::endl; unsigned char* image = SOIL_load_image("container.jpg", &width, &height, 0, SOIL_LOAD_RGB); std::cout << SOIL_last_result() << std::endl; if (image) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image); //第一个参数纹理目标Target,会生成与当前绑定纹理对象同样纹理 //设置纹理指定多级渐远纹理级别,0,基本级别 //第三个参数,纹理储存为何种格式,RGB //四五是设置最终的纹理的宽度和高度,就用之前的变量。 //0 //七八位源图的格式和数据类型,使用RGB加载并储存为char(byte)数组 //最后参数为图像的数据 } else { std::cout << "Failed to load texture." << std::endl; } //当前绑定的纹理对象会被附加上纹理图像,然而只有0级别的纹理图像被加载 了,多级的话需要手动设置 //或者可以,在生成纹理之后调用glGenerateMipmap,这会为当前绑定的纹理自动生成所有需要的多级渐远纹理。 glGenerateMipmap(GL_TEXTURE_2D); SOIL_free_image_data(image); glBindTexture(GL_TEXTURE_2D, 0); glGenTextures(1, &texture2); glBindTexture(GL_TEXTURE_2D, texture2); 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 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); image = SOIL_load_image("awesomeface.png", &width, &height, 0, SOIL_LOAD_RGB); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image); glGenerateMipmap(GL_TEXTURE_2D); SOIL_free_image_data(image); glBindTexture(GL_TEXTURE_2D, 0); //防止退出的循环 while (!glfwWindowShouldClose(window)) { glfwPollEvents(); glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); //glClearColor是一个状态设置函数,glClear是一个状态应用函数 //绘图 ourShader.Use(); glUniform1f(glGetUniformLocation(ourShader.Program, "para"), Offset); //把变换矩阵传递给着色器 GLuint transformLoc = glGetUniformLocation(ourShader.Program, "transform"); glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans)); //参数一是uniform的值,第二是矩阵个数,3,列主序矩阵不许置换4,变化一下数据 glActiveTexture(GL_TEXTURE0);//这句是激活。 glBindTexture(GL_TEXTURE_2D, texture1); glUniform1i(glGetUniformLocation(ourShader.Program, "ourTexture1"), 0); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, texture2); glUniform1i(glGetUniformLocation(ourShader.Program, "ourTexture2"), 1); //这里因为要使用第二个纹理,改变一点渲染流程,先绑定两个纹理到对应的纹理单元,然后定义哪个uniform采样器应对哪个纹理单元。 glBindVertexArray(VAO); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); glBindVertexArray(0); glfwSwapBuffers(window); } //回调函数 //释放: glDeleteVertexArrays(1, &VAO); glDeleteBuffers(1, &VBO); glDeleteBuffers(1, &EBO); glfwTerminate(); //释放/删除之前的分配的所有资源 return 0;}void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode){ std::cout << key << std::endl; //用户按下ESC键,我们设置window窗口WindowShouldClose属性为true //关闭应用程序 if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) glfwSetWindowShouldClose(window, GL_TRUE); if (key == GLFW_KEY_UP&&action == GLFW_PRESS) { Offset += 0.1; if (Offset >= 1.0f) Offset = 1.0f; } if (key == GLFW_KEY_DOWN&&action == GLFW_PRESS) { Offset -= 0.1; if (Offset <= 0.0f) Offset = 0.0f; }}

着色器:

#version 330 corelayout(location = 0) in vec3 position;layout(location = 1) in vec3 color;layout(location = 2) in vec2 texCoord;out vec3 ourColor;out vec2 TexCoord;uniform mat4 transform;void main(){ gl_Position = transform * vec4(position, 1.0f); ourColor = color; TexCoord = vec2(1.0f-texCoord.x, 1.0f-texCoord.y);}

然后让他根据开始运行时间旋转,每秒转50度。

在游戏循环里加上代码:

glm::mat4 trans;trans = glm::translate(trans, glm::vec3(0.5f, -0.5f, 0.0f));trans = glm::rotate(trans, glm::radians((GLfloat)glfwGetTime()*50.0f), glm::vec3(0.0f, 0.0f, 1.0f));//尽管在代码中我们先位移再旋转,实际的变换却是先应用旋转再是位移的。//glfwGetTime(); 获取一个从glfw初始化完到当前的一个时间秒数

练习:

1.使用应用在箱子上的最后一个变换,尝试将其改变为先旋转,后位移。看看发生了什么,试着想想为什么会发生这样的事情: Remember that matrix multiplication is applied in reverse. This time a translation is thus applied first to the container positioning it in the bottom-right corner of the screen. After the translation the rotation is applied to the translated container. A rotation transformation is also known as a change-of-basis transformation for when we dig a bit deeper into linear algebra. Since we're changing the basis of the container, the next resulting translations will translate the container based on the new basis vectors. Once the vector is slightly rotated, the vertical translations would also be slightly translated for example. If we would first apply rotations then they'd resolve around the rotation origin (0,0,0), but  since the container is first translated, its rotation origin is no longer (0,0,0) making it looks as if its circling around the origin of the scene.

这块确实挺复杂的需要好好想想。

2.尝试再次调用glDrawElements画出第二个箱子,只使用变换将其摆放在不同的位置。让这个箱子被摆放在窗口的左上角,并且会不断的缩放(而不是旋转)。sin函数在这里会很有用,不过注意使用sin函数时应用负值会导致物体被翻转。

glm::mat4 transform = glm::mat4();transform = glm::translate(transform, glm::vec3(-0.5f, 0.5f, 0.0f));GLfloat scaleAmount = sin(glfwGetTime());transform = glm::scale(transform, glm::vec3(scaleAmount, scaleAmount, scaleAmount));glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(transform));glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:纹理
下一篇:PHP中文件读、写、删的操作(PHP中对文件和目录操作)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~