OpenGL入门

OpenGL

  1. 下载2个库;

  2. [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qirK307r-1572488193089)(D:\Study\openGL学习\1.png)]

  3. [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OPyufy5C-1572488193090)(D:\Study\openGL学习\2.png)]

  4. [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XgU4YDd4-1572488193090)(D:\Study\openGL学习\3.png)]

  5. 一个物件一个VAO 顶点数组对象

  6. VBO 顶点缓冲对象;

    1. 使用这些缓冲对象的好处是我们可以一次性的发送一大批数据到显卡上,而不是每个顶点发送一次。从CPU把数据发送到显卡相对较慢,所以只要可能我们都要尝试尽量一次性发送尽可能多的数据。所以我们可以使用glGenBuffers函数和一个缓冲ID生成一个VBO对象

      unsigned int VBO;
      glGenBuffers(1, &VBO);
      
    2. 顶点缓冲对象的缓冲类型是GL_ARRAY_BUFFER。OpenGL允许我们同时绑定多个缓冲,只要它们是不同的缓冲类型。我们可以使用glBindBuffer函数把新创建的缓冲绑定到GL_ARRAY_BUFFER目标上:

      glBindBuffer(GL_ARRAY_BUFFER, VBO);  
      
    3. 从这一刻起,我们使用的任何(在GL_ARRAY_BUFFER目标上的)缓冲调用都会用来配置当前绑定的缓冲(VBO)。然后我们可以调用glBufferData函数,它会把之前定义的顶点数据复制到缓冲的内存中:

      glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
      
  7. 顶点着色器;

    #version 330 core
    layout (location = 0) in vec3 aPos;
    void main()
    {
        gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
    }
    
  8. 编译着色器;

    unsigned int vertexShader;
    vertexShader = glCreateShader(GL_VERTEX_SHADER);
    
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    glCompileShader(vertexShader);
    
  9. 片段着色器;

    #version 330 core
    out vec4 FragColor;
    void main()
    {
        FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);
    } 
    
  10. 着色器程序;

    unsigned int shaderProgram;
    shaderProgram = glCreateProgram();
    
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);
    
    glUseProgram(shaderProgram);
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);
    
  11. 链接顶点属性;

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    
  12. 顶点数组对象: VAO 去 VBO 挖;

    unsigned int VAO;
    glGenVertexArrays(1, &VAO);
    
    // ..:: 初始化代码(只运行一次 (除非你的物体频繁改变)) :: ..
    // 1. 绑定VAO
    glBindVertexArray(VAO);
    // 2. 把顶点数组复制到缓冲中供OpenGL使用
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    // 3. 设置顶点属性指针
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    
    [...]
    
    // ..:: 绘制代码(渲染循环中) :: ..
    // 4. 绘制物体
    glUseProgram(shaderProgram);
    glBindVertexArray(VAO);
    someOpenGLFunctionThatDrawsOurTriangle();
    
    glUseProgram(shaderProgram);
    glBindVertexArray(VAO);
    glDrawArrays(GL_TRIANGLES, 0, 3);
    

  1. OPENGL 是逆时针作为画三角的正面;

    float vertices[] = {
    	-0.5f, -0.5f, 0.0f,
    	 0.5f, -0.5f, 0.0f,
    	 0.0f,  0.5f, 0.0f,
    
    	// 0.5f,-0.5f,0.0f, //顺序错误,逆时针画;这样画出来是背面
    	 //0.0f,  0.5f, 0.0f,
    	 0.8f,0.8f,0.0f
    };
    unsigned int indices[] = {  //索引数组;
    	0,1,2, //第一个三角形
    	2,1,3  //第二个三角形
    }
    
  2. 如果画一个四边形,画两个三角形会多于2个点 占用内存;引入EBO:

    1. EBO:索引缓冲对象

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u8cyo6f8-1572488193091)(D:\Study\openGL学习\4.png)]

    2. unsigned int EBO;  //索引缓冲对象
      	glGenBuffers(1, &EBO);
      	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
      	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
      
    3. 开始画

      		glUseProgram(shaderProgram);
      		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
      		glBindVertexArray(VAO);
      		//glDrawArrays(GL_TRIANGLES, 0, 6);
      		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);	
      

  1. Shade

    #version version_number
    in type in_variable_name;
    in type in_variable_name;
    
    out type out_variable_name;
    
    uniform type uniform_name; //主要做时钟
    
    int main()
    {
      // 处理输入并进行一些图形操作
      ...
      // 输出处理过的结果到输出变量
      out_variable_name = weird_stuff_we_processed;
    }
    
  2. 顶点着色器的 out 属性 必须和片段着色器 in对应

    //顶点着色器
    const char* vertexShaderSource = 
    "#version 330 core                                       \n	   "
    "layout(location = 0) in vec3 aPos;                     \n	   "
    "out vec4 vertexColor;									\n"//this
    "void main() {\n											   "
    "		gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);	\n"
    "		vertexColor = vec4(1.0,0,0,1.0);		\n"
    "}\n	   ";
    //片段着色器  ,对每一个像素着色
    const char* fragmentShaderSource =
    "#version 330 core                              \n	  "
    "in vec4 vertexColor;							\n" //this 接收
    "out vec4 FragColor;                            \n	  "
    "void main() {\n									  "
    "		FragColor = vertexColor;} \n ";  //使用变量
    
  3. uniform 从CPU直接向GPU灌数据; 从外部

    //片段着色器  ,对每一个像素着色
    const char* fragmentShaderSource =
    "#version 330 core                              \n	  "
    "in vec4 vertexColor;							\n"
    "uniform vec4 ourColor;							\n"   //this
    "out vec4 FragColor;                            \n	  "
    "void main() {\n									  "
    "		FragColor = ourColor;} \n ";  //this
    

    CPU:

    float timeValue = glfwGetTime();
    float greenValue = (sin(timeValue) / 2.0f) + 0.5f;//动态改变颜色
    int vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor");
    glUseProgram(shaderProgram);
    glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f);
    
  4. 插值:更多的颜色,往顶点数组新增3个属性,RGB;

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KEqbV06z-1572488193091)(D:\Study\openGL学习\5.png)]

    修改挖顶点偏移量和步长

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);  //挖顶点   但是增加了颜色后 步长要变;
    glEnableVertexAttribArray(0);
    
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*) (3*sizeof(float)));  //挖颜色  步长变,起始偏移变
    glEnableVertexAttribArray(1);
    
    //顶点着色器
    const char* vertexShaderSource = 
    "#version 330 core                                       \n	   "
    "layout(location = 0) in vec3 aPos;                     \n	   "
    "layout(location = 1) in vec3 aColor;                     \n	   "//this
    "out vec4 vertexColor;									\n"
    "void main() {\n											   "
    "		gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);	\n"
    "		vertexColor = vec4(aColor.x, aColor.y, aColor.z, 1.0);\n " // this
    "}\n	   ";
    

C++文件流读取着色器内容:

做一个shader类:

  1. .h类似于接口(此接口还可以实现方法???) .cpp继承类;

  2. 别的文件调用接口方法就行 用双引号引本项目下的接口;三角括号给系统用的;

    #include "Shader.h"
    
  3. 若用 new 产生的类,必须用*接受,而且用方法得 ->;

  4. 如果直接 产生的类 ,用.就能使用方法;

C++文件流

  1. [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GyG8j9jl-1572488193091)(D:\Study\openGL学习\6.png)]

  2. #include<fstream>
    std::ifstream vertexFile;  
    std::ifstream fragmentFile;      //定义流
    vertexFile.open(vertexPath);    //打开文件 ,只是注册并不是读入内存;
    fragmentFile.open(fragmentPath);
    
    std::stringstream vertextSStream; // 定义string接收;
    std::stringstream fragmentSStream; // 定义string接收;
    
    vertexFile.exceptions(std::ifstream::fail||std::ifstream::badbit); //逻辑错误或者文件损坏
    fragmentFile.exceptions(std::ifstream::fail || std::ifstream::badbit);
    try    //异常处理
    	{
    		if (!vertexFile.is_open()||!fragmentFile.is_open())
    		{
    			throw std::exception("open file error");
    		}
       		 vertextSStream << vertexFile.rdbuf(); //从硬盘读入内存的stringbuffer
    		fragmentSStream << fragmentFile.rdbuf(); //从硬盘读入内存
        ---------------------------
       		 vertextString = vertextSStream.str(); //把stringbuffer里面的内容转为String塞入变量;
    		fragmentString = fragmentSStream.str();
        -----------------------------
        	vertexSource = vertextString.c_str();// string转为 字符数组 塞入变量;
    		fragmentSource = fragmentString.c_str();
        
        ---------------------------------
            unsigned int vertex, fragment;
    
    		vertex = glCreateShader(GL_VERTEX_SHADER);  //顶点着色器
    		glShaderSource(vertex, 1, &vertexSource, NULL);
     	glCompileShader(vertex);// 把shader从源代码转为二进制;
    		checkCompileErrors(vertex, "VERTEX");
    
    		fragment = glCreateShader(GL_FRAGMENT_SHADER); //片段着色器
    		glShaderSource(fragment, 1, &fragmentSource, NULL);
    		glCompileShader(fragment);
    		checkCompileErrors(fragment, "FRAGMENT");
    
    		ID = glCreateProgram(); //二进制的链接   着色器程序
    		glAttachShader(ID, vertex);
    		glAttachShader(ID, fragment);
    		glLinkProgram(ID);
    		checkCompileErrors(ID, "PROGRAM");
    		glDeleteShader(vertex);   //已经连接到程序中 不在需要;
    		glDeleteShader(fragment);
    	}
    	catch (const std::exception& ex)
    	{
    		printf(ex.what());
    	}
    
    void Shader::use() {
    	glUseProgram(ID);
    }
    
    void Shader::checkCompileErrors(unsigned int ID, std::string type) {
    	int success;
    	char infoLog[512];
    	if (type != "PROGRAM")
    	{
    		glGetShaderiv(ID, GL_COMPILE_STATUS, &success);
    		if (!success) {
    			glGetShaderInfoLog(ID, 512, NULL, infoLog);
    			std::cout << "shader compile error:" << infoLog << std::endl;
    		}
    	}
    	else
    	{
    		glGetProgramiv(ID, GL_LINK_STATUS,&success);
    		if (!success) {
    			glGetProgramInfoLog(ID, 512, NULL, infoLog);
    			std::cout << "program linking error:" << infoLog << std::endl;
    		}
    	}
    }
    

纹理:textures

  1. 使用#include “stb_image.h” 库;

  2. U,V坐标 (0-1)[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kBSbGrWS-1572488193091)(D:\Study\openGL学习\7.png)]

  3. 纹理环绕方式:

    1. repeat:重复图像 ,超过1自动重复;
    2. clamp:采边缘点 蔓延出去;
    3. mirror : 偶数次翻转
  4. 纹理过滤: 如相机离很远的时候

    1. 邻近过滤(默认)

    2. 线性过滤 : 更平滑

    3. 多级渐远纹理 : 距离超过一定的阈值,不计算了 直接换

      两个不同级别的多级渐远纹理层之间会产生不真实的生硬边界。就像普通的纹理过滤一样,切换多级渐远纹理级别时你也可以在两个不同多级渐远纹理级别之间使用NEAREST和LINEAR过滤。

  5. 代码

    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float))); //挖纹理 注意步长和起始偏移
    glEnableVertexAttribArray(2);
    
    #version 330 core                                         
    layout(location = 0) in vec3 aPos;                       
    layout(location = 1) in vec3 aColor;     
    layout(location = 2) in vec2 aTexCoord;     //this
    out vec4 vertexColor;	
    out vec2 TexCoord;   //this
    void main() {										   
    		gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
    		vertexColor = vec4(aColor.x, aColor.y, aColor.z, 1.0);	
    		TexCoord = aTexCoord;  //this
    }
    //然后去fragment接收
    #version 330 core                 
    in vec4 vertexColor;	
    in vec2 TexCoord   //this
    
    uniform sample2D ourTexture;  //this   传入的纹理号;默认0
    
    out vec4 FragColor;               
    void main() {					
    		//FragColor = vertexColor;
    		FragColor = texture(ourTexture,TexCoord);  //this 此方法
    }
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lgFwMa9h-1572488193092)(D:\Study\openGL学习\8.png)]

  6. 绑定图片

    // 绑定图片
    unsigned int TexBuffer;
    	glGenTextures(1, &TexBufferA);
    	glBindTexture(GL_TEXTURE_2D, TexBufferA);
    
    int width, height, nrChannel;
    unsigned char* data = stbi_load("test.jpg", &width, &height, &nrChannel, 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 << "load image failed." << std::endl;
    }
    stbi_image_free(data);
    ---------------------------------
    while:glBindTexture(GL_TEXTURE_2D, TexBuffer);
    
  7. 开启贴2张图:

    1. [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zq7wHCO9-1572488193094)(D:\Study\openGL学习\9.png)]

    2. unsigned int TexBufferA;
      glGenTextures(1, &TexBufferA);
      glBindTexture(GL_TEXTURE_2D, TexBufferA);
      int width, height, nrChannel;
      unsigned char* data = stbi_load("test.jpg", &width, &height, &nrChannel, 0);
      
      unsigned int TexBufferB;
      glGenTextures(1, &TexBufferB);
      glBindTexture(GL_TEXTURE_2D, TexBufferB);
      unsigned char* data2 = stbi_load("test1.jpg", &width, &height, &nrChannel, 0);
      
      while:
      glActiveTexture(GL_TEXTURE0);//开启0号匝位;
      glBindTexture(GL_TEXTURE_2D, TexBufferA);
      glActiveTexture(GL_TEXTURE3);//开启3号匝位;
      glBindTexture(GL_TEXTURE_2D, TexBufferB);
      
      myShader->use();
      glUniform1i(glGetUniformLocation(myShader->ID,"ourTexture"),0);
      glUniform1i(glGetUniformLocation(myShader->ID, "ourFace"), 3); // 手动设置
      
      Source:
      #version 330 core                                         
      layout(location = 0) in vec3 aPos;        //layout就是挖               
      layout(location = 1) in vec3 aColor;     
      layout(location = 2) in vec2 aTexCoord;   this
      
      out vec4 vertexColor;	
      out vec2 TexCoord;
      void main() {										   
      		gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
      		vertexColor = vec4(aColor.x, aColor.y, aColor.z, 1.0);	
      		TexCoord = aTexCoord; this
      }
      
      #version 330 core      
      out vec4 FragColor; 
      in vec4 vertexColor;	
      in vec2 TexCoord;
      
      uniform sampler2D ourTexture;  this 
      uniform sampler2D ourFace; this
              
      void main() {					
      		//FragColor = vertexColor;
      		FragColor = texture(ourTexture,TexCoord)* texture(ourFace,TexCoord) ;
      }
      

矩阵变换:

  1. 向量点乘:dot(a,b)[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pFCGkv5l-1572488193096)(D:\Study\openGL学习\10.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BafokWbn-1572488193098)(D:\Study\openGL学习\11.png)]点乘就是拿来计算夹角的;

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1dy1Tx2U-1572488193098)(D:\Study\openGL学习\12.png)]反三角

  2. 向量叉乘:cross(a,b) 可以得到同事垂直于这两个向量的向量;正交于这两个向量

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZZmEo103-1572488193099)(D:\Study\openGL学习\13.png)]

  3. 向量 乘以 矩阵 把向量看成一维矩阵!~ (实则是 矩阵乘以向量(右边))

  4. GLSL的 vec4 ***** vec4 是逐元乘法; **************

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hUDTTVGW-1572488193099)(D:\Study\openGL学习\14.png)]

  5. 向量缩放用变换矩阵的对角线即可;

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bADb3M5y-1572488193099)(D:\Study\openGL学习\15.png)]

  6. 向量位移:第四列最上面的3个值;这就是4x4的好处; 如果是位置w补1,速度补0

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JpNWf5kK-1572488193099)(D:\Study\openGL学习\16.png)]

  7. 弧度转角度:角度 = 弧度 * (180.0f / PI)

  8. 角度转弧度:弧度 = 角度 * (PI / 180.0f)

  9. 旋转[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gSHMWUel-1572488193099)(D:\Study\openGL学习\17.png)]

  10. 引入glm头文件;

    #include <glm/glm/glm.hpp>
    #include <glm/glm/gtc/matrix_transform.hpp>
    #include <glm/glm/gtc/type_ptr.hpp>
    	glm::vec4 vec(1.0f, 0, 0, 1.0f);
    	glm::mat4 trans; //单位4x4矩阵
    	trans = glm::translate(trans, glm::vec3(2.0f, 0, 0));//把向量转为位移矩阵
    	vec = trans * vec;
    

    要做旋转矩阵

    uniform mat4 transform; //在vertexSource里面;
    gl_Position = transform * vec4(aPos.x, aPos.y, aPos.z, 1.0);
    
    //在while里面;
    glm::mat4 trans;
    glUniformMatrix4fv(glGetUniformLocation(myShader->ID, "transform"), 1, GL_FALSE, glm::value_ptr(trans));
    //while 外面:写在while里面就是动态的;
    glm::mat4 trans;
    trans = glm::translate(trans, glm::vec3(-1.0f, 0, 0));//位移  参数相加
    trans = glm::rotate(trans, glm::radians(45.0f), glm::vec3(0, 0, 1.0f));//旋转角度与轴
    trans = glm::rotate(trans,(float)glfwGetTime(), glm::vec3(0, 0, 1.0f));
    //硬是把时间强转为弧度量一直转;
    trans = glm::scale(trans, glm::vec3(2.0f, 2.0f, 2.0f));//放大 参数为倍数
    

    矩阵的组合:把多个动作组合到一起; 代码先缩放,再旋转,最后是位移;规定!

    但是:矩阵的运算方式是从右到左,所以顺序相反;

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tc1CIeno-1572488193099)(D:\Study\openGL学习\18.png)]


坐标系统:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XrfD0K8o-1572488193100)(D:\Study\openGL学习\19.png)]

  1. LocalSpace 局部空间 :以物体中心为原点的坐标;当需要对物体进行修改的时候;

  2. WorldSpace 世界空间 :希望将物体分散在世界上摆放,该变换是由模型矩阵(Model Matrix)实现的

  3. ViewSpace 观察空间 :将世界空间坐标转化为用户视野前方的坐标而产生的结果,

    由观察矩阵(View Matrix),它被用来将世界坐标变换到观察空间;

  4. ClipSpace 裁剪空间 : 只渲染镜头前的,其余的cut调;看不见的裁剪掉;

    为了将顶点坐标从观察变换到裁剪空间,我们需要定义一个投影矩阵(Projection Matrix)

    一旦所有顶点被变换到裁剪空间,最终的操作——透视除法(Perspective Division)将会执行,在这个过程中我们将位置向量的x,y,z分量分别除以向量的齐次w分量.

  5. ScreenSpace 屏幕空间 :透视投影矩阵,这个投影矩阵将给定的平截头体范围映射到裁剪空间,除此之外还修改了每个顶点坐标的w值,从而使得离观察者越远的顶点坐标w分量越大。

    顶点坐标的每个分量都会除以它的w分量,距离观察者越远顶点坐标就会越小。

    opengl会进行自动除法和裁剪:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z3UcjjdL-1572488193100)(D:\Study\openGL学习\20.png)]这是也是w分量非常重要的另一个原因;

    glm::mat4 obj = 
        glm::perspective(glm::radians(45.0f), (float)width/(float)height, 0.1f, 100.0f); 
    //参数1:FOV,视角通常设置为45.0f;参数2:宽高比;参数34:近和远平面
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XyeoSDoH-1572488193100)(D:\Study\openGL学习\21.png)]

  6. 操作3矩阵:代码:

    //while外定义
    glm::mat4 modelMat;
    modelMat = glm::rotate(modelMat, glm::radians(-55.0f), glm::vec3(1.0f, 0, 0));
    glm::mat4 viewMat;
    viewMat = glm::translate(viewMat, glm::vec3(0, 0, -3.0f));
    glm::mat4 projMat;
    projMat = glm::perspective(glm::radians(45.0f), (float)800.0f / 600.0f, 0.1f, 100.0f);
    //vertexSOurce写逻辑
    uniform mat4 modelMat;
    uniform mat4 viewMat;
    uniform mat4 projMat;
    
    gl_Position =projMat * viewMat * modelMat * vec4(aPos.x, aPos.y, aPos.z, 1.0);
    //while中塞入
    glUniformMatrix4fv(glGetUniformLocation(myShader->ID, "modelMat"), 1, GL_FALSE, glm::value_ptr(modelMat));
    glUniformMatrix4fv(glGetUniformLocation(myShader->ID, "viewMat"), 1, GL_FALSE, glm::value_ptr(viewMat));
    glUniformMatrix4fv(glGetUniformLocation(myShader->ID, "projMat"), 1, GL_FALSE, glm::value_ptr(projMat));
    
  7. 缩放[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s6OkIMIc-1572488193100)(D:\Study\openGL学习\23.png)]

  8. 转换完要保存一个深度信息;–Z缓冲

    glEnable(GL_DEPTH_TEST);//开启深度缓冲,防止后画的画覆盖前面画的画;、
    //while里面
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//清颜色缓存+更新深度缓冲
    
  9. 画10个就for10次draw;


Camera:

  1. pitch 吐痰 yaw摇头 一般不会旋转摄像头

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kbp2jq9Y-1572488193101)(D:\Study\openGL学习\25.png)]

  2. 描述相机位置的四个参数

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sn79t8Yc-1572488193101)(D:\Study\openGL学习\26.png)]

  3. 通过摄像机获得ViewMatrix

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dOd2tEq4-1572488193102)(D:\Study\openGL学习\27.png)]

  4. 代码

    1. 添加Camera类

      class Camera
      {
      public:
      	Camera(glm::vec3 position, glm::vec3 target, glm::vec3 worldup);
      	~Camera();
      
      	glm::vec3 Position;
      	glm::vec3 Forward;
      	glm::vec3 Right;
      	glm::vec3 Up;
      	glm::vec3 WorldUp;
      	float Pitch;
      	float Yaw;
          float SenseX = 0.01f; //灵敏度
      	float SenseY = 0.01f;
          float speedZ = 0; //定义相机移动
      	glm::mat4 GetViewMatrix();
          void ProcessMouseMovement(float deltaX, float deltaY);//更新坐标
        private:
      	void UpdateCameraVectors();//更新相机
      };
      -----------------------------------------------------------------------
       //普通
          Camera::Camera(glm::vec3 position, glm::vec3 target, glm::vec3 worldup) {
      	Position = position;
      	WorldUp = worldup;
      	Forward = glm::normalize(target - position);
      	Right =glm::normalize(glm::cross(Forward, WorldUp));// 叉乘,并初始化为单位向量
      	Up = glm::normalize(glm::cross(Forward, Right));
      	
      }
      -----------------------------------------------------------------------
          Camera::Camera(glm::vec3 position, float pitch, float yaw, glm::vec3 worldup) {//欧拉角版本
      	Position = position;
      	WorldUp = worldup;
          Pitch = pitch;
      	Yaw = yaw;
      	Forward.x = glm::cos(pitch) * glm::sin(yaw);
      	Forward.y = glm::sin(pitch);
      	Forward.z = glm::cos(pitch) * glm::cos(yaw);
      	Right = glm::normalize(glm::cross(Forward, WorldUp));// 叉乘,并初始化为单位向量
      	Up = glm::normalize(glm::cross(Forward, Right));
      }
      ------------------------------
      glm::mat4 Camera::GetViewMatrix() {  //用lookat获得viewmatrix;
      	return glm::lookAt(Position, Position + Forward, WorldUp);
      }
      void Camera::UpdateCameraVectors(){
      	Forward.x = glm::cos(Pitch) * glm::sin(Yaw);
      	Forward.y = glm::sin(Pitch);
      	Forward.z = glm::cos(Pitch) * glm::cos(Yaw);
      	Right = glm::normalize(glm::cross(Forward, WorldUp));// 叉乘,并初始化为单位向量
      	Up = glm::normalize(glm::cross(Forward, Right));
      }
      void Camera::ProcessMouseMovement(float deltaX, float deltaY) {//用于更新坐标
      	Pitch -= deltaY * SenseY;//*灵敏度
      

    Yaw -= deltaX * SenseX;
    UpdateCameraVectors();//更新参数;
    }

    
    main中使用:
    
    ```c++
    //宣告摄像头
    Camera camera(glm::vec3(0, 0, 3.0f), glm::vec3(0, 0, 0), glm::vec3(0, 1.0f, 0));
    viewMat = camera.GetViewMatrix();
    ----------------------------
    

//宣告欧拉摄像头 中间两个单位为度数
Camera camera(glm::vec3(0, 0, 3.0f), glm::radians(-44.0f), glm::radians(180.0f), glm::vec3(0, 1.0f, 0));
viewMat = camera.GetViewMatrix();


--------------



读取鼠标输入

```c++
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);//关掉鼠标显示

float lastX;//定义前一次的坐标;
float lastY;
bool firstMouse = true; //第一次运行
void mouse_callback(GLFWwindow* window, double xpos, double ypos) {
 if (firstMouse == true) {
 	lastX = xPos;
 	lastY = yPos;
 	firstMouse = false;
 }
 float deltaX, deltaY;
 deltaX = xpos - lastX;//差值
 deltaY = ypos - lastY;
 lastX = xpos;
 lastY = ypos;
 camera.ProcessMouseMovement(deltaX,deltaY);//更新坐标
}
glfwSetCursorPosCallback(window, mouse_callback);//注册回调函数

----------------------------------------------------------------
while 回圈:
viewMat = camera.GetViewMatrix();//动态更新相机

移动相机:

camera.h
float speedZ = 0; //相机移动;
void UpdateCameraPos();
-------------------------------------
camera.cpp
void Camera::UpdateCameraPos() {
	Position += Forward * speedZ * 0.001f;
}
----------------------------------
main.cpp
void processInput(GLFWwindow* window) {
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
		glfwSetWindowShouldClose(window, true);
	}
	if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) {
		camera.speedZ = 1.0f;
	}
	else if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) {
		camera.speedZ = -1.0f;
	}
	else {
		camera.speedZ = 0;
	}
}

while 回圈:
viewMat = camera.GetViewMatrix();//动态更新相机


--------------------------------------------

移动相机:

```c++
camera.h
float speedZ = 0; //相机移动;
void UpdateCameraPos();
-------------------------------------
camera.cpp
void Camera::UpdateCameraPos() {
	Position += Forward * speedZ * 0.001f;
}
----------------------------------
main.cpp
void processInput(GLFWwindow* window) {
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
		glfwSetWindowShouldClose(window, true);
	}
	if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) {
		camera.speedZ = 1.0f;
	}
	else if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) {
		camera.speedZ = -1.0f;
	}
	else {
		camera.speedZ = 0;
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值