计算机图形学——模型及基础知识

1、库文件:

1、(VC++ 目录)选项卡——包含目录

assimp:

D:\app\Assimp\assimp\include

glfw

D:\360Downloads\glfw-3.3.bin.WIN32\include

glew

D:\360Downloads\glew-2.1.0-win32\glew-2.1.0\include

2、(VC++ 目录)选项卡——库文件

assimp:

D:\VS2017工作夹\Project_dazuoye\Debug

glfw

D:\360Downloads\glfw-3.3.bin.WIN32\lib-vc2015

glew

D:\360Downloads\glew-2.1.0-win32\glew-2.1.0\lib\Release\Win32

3、(C/C++ )选项卡——附加包含文件

glm:

D:\VS2017工作夹\Project5_bianhuan\Project1\glm

4、链接器——附加库文件

soil:

D:\google\SpartanJ-soil2-2aeaad5b7c94\lib

5、链接器——输入——附加依赖项

opengl32.lib
glfw3.lib
glew32s.lib
soil2-debug.lib
assimp-vc141-mtd.lib

6、链接器——输入——忽略特定依赖项

MSVCRT.lib

2、重要函数

1、glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,3 * sizeof(GLfloat), (GLvoid *)0);  

//0: 对应调色器里 location 的值;3: 对应 vec3 三个量;GL_FLOAT: 浮点型;GL_FALSE:;3*sizeof(GLfloat): 对应 Buffer 里传的数据;(GLvoid*)0: 从第 0 个位置开始

2、glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

使用glDrawElements时,我们会使用当前绑定的索引缓冲对象中的索引进行绘制:

第一个参数指定了我们绘制的模式,这个和glDrawArrays的一样。第二个参数是我们打算绘制顶点的个数,这里填6,也就是说我们一共需要绘制6个顶点。第三个参数是索引的类型,这里是GL_UNSIGNED_INT。最后一个参数里我们可以指定EBO中的偏移量(或者传递一个索引数组,但是这是当你不在使用索引缓冲对象的时候),但是我们会在这里填写0。

3、glDrawArrays(GL_TRIANGLES, 0, 3);

glDrawArrays函数第一个参数是我们打算绘制的OpenGL图元的类型。由于我们在一开始时说过,我们希望绘制的是一个三角形,这里传递GL_TRIANGLES给它。第二个参数指定了顶点数组的起始索引,我们这里填0。最后一个参数指定我们打算绘制多少个顶点,这里是3(我们只从我们的数据中渲染一个三角形,它只有3个顶点长)。

4、

int width, height;
unsigned char* image = SOIL_load_image("2.jpg", 
		&width, &height, 0, SOIL_LOAD_RGBA);  // 读取它的 RGBA 信息

这个函数首先接受一个图像文件的位置作为输入。接下来它需要三个int作为它的第二、第三和第四个参数,stb_image.h将会用图像的宽度高度颜色通道的个数填充这三个变量。我们之后生成纹理的时候会用到的图像的宽度和高度的。

5、我们可以使用前面载入的图片数据生成一个纹理了。纹理可以通过glTexImage2D来生成:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);

函数很长,参数也不少,所以我们一个一个地讲解:

  • 第一个参数指定了纹理目标(Target)。设置为GL_TEXTURE_2D意味着会生成与当前绑定的纹理对象在同一个目标上的纹理(任何绑定到GL_TEXTURE_1D和GL_TEXTURE_3D的纹理不会受到影响)。
  • 第二个参数为纹理指定多级渐远纹理的级别,如果你希望单独手动设置每个多级渐远纹理的级别的话。这里我们填0,也就是基本级别。
  • 第三个参数告诉OpenGL我们希望把纹理储存为何种格式。我们的图像只有RGB值,因此我们也把纹理储存为RGB值。
  • 第四个和第五个参数设置最终的纹理的宽度和高度。我们之前加载图像的时候储存了它们,所以我们使用对应的变量。
  • 下个参数应该总是被设为0(历史遗留的问题)。
  • 第七第八个参数定义了源图的格式和数据类型。我们使用RGB值加载这个图像,并把它们储存为char(byte)数组,我们将会传入对应值。
  • 最后一个参数是真正的图像数据。

当调用glTexImage2D时,当前绑定的纹理对象就会被附加上纹理图像。然而,目前只有基本级别(Base-level)的纹理图像被加载了,如果要使用多级渐远纹理,我们必须手动设置所有不同的图像(不断递增第二个参数)。或者,直接在生成纹理之后调用glGenerateMipmap。这会为当前绑定的纹理自动生成所有需要的多级渐远纹理。

6、

unsigned int transformLoc = glGetUniformLocation(ourShader.ID, "transform");
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans));

我们首先查询uniform变量的地址,然后用有Matrix4fv后缀的glUniform函数把矩阵数据发送给着色器。第一个参数你现在应该很熟悉了,它是uniform的位置值。第二个参数告诉OpenGL我们将要发送多少个矩阵,这里是1。

3、常识

1、当调用glClear函数,清除颜色缓冲之后,整个颜色缓冲都会被填充为glClearColor里所设置的颜色。

2、注意vec.w分量不是用作表达空间中的位置的(我们处理的是3D不是4D),而是用在所谓透视除法(Perspective Division)上,1.0代表完全不透明)

3、在计算机图形中颜色被表示为有4个元素的数组:红色、绿色、蓝色和alpha(透明度)分量,通常缩写为RGBA。当在OpenGL或GLSL中定义一个颜色的时候,我们把颜色每个分量的强度设置在0.0到1.0之间。比如说我们设置红为1.0f,绿为1.0f,我们会得到两个颜色的混合色,即黄色。这三种颜色分量的不同调配可以生成超过1600万种不同的颜色!

4、一个向量的分量可以通过vec.x这种方式获取,这里x是指这个向量的第一个分量。你可以分别使用.x.y.z.w来获取它们的第1、2、3、4个分量。mat4类型的trans,默认是一个4×4单位矩阵。
5、如果我们把缩放变量表示为(S1,S2,S3)(S1,S2,S3)我们可以为任意向量(x,y,z)(x,y,z)定义一个缩放矩阵:
6、纹理坐标在x和y轴上,范围为0到1之间(注意我们使用的是2D纹理图像)。使用纹理坐标获取纹理颜色叫做采样(Sampling)。纹理坐标起始于(0, 0),也就是纹理图片的左下角,终始于(1, 1),即纹理图片的右上角。下面的图片展示了我们是如何把纹理坐标映射到三角形上的。
7、要定义一个摄像机,我们需要它在世界空间中的位置、观察的方向、一个指向它右测的向量以及一个指向它上方的向量。
我们先来尝试缩放向量v¯=(3,2)v¯=(3,2)。我们可以把向量沿着x轴缩放0.5,使它的宽度缩小为原来的二分之一;

8、第四个缩放向量仍然是1,因为在3D空间中缩放w分量是无意义的。w分量另有其他用途,在后面我们会看到。
glm::mat4 trans;
trans = glm::translate(trans, glm::vec3(0.5f, -0.5f, 0.0f));
trans = glm::rotate(trans, (float)glfwGetTime(), glm::vec3(0.0f, 0.0f, 1.0f));

9、我们使用一个很小的常量(光照)颜色,添加到物体片段的最终颜色中,这样子的话即便场景中没有直接的光源也能看起来存在有一些发散的光。把环境光照添加到场景里非常简单。我们用光的颜色乘以一个很小的常量环境因子,再乘以物体的颜色,然后将最终结果作为片段的颜色:

void main()
{
    float ambientStrength = 0.1;
    vec3 ambient = ambientStrength * lightColor;

    vec3 result = ambient * objectColor;
    FragColor = vec4(result, 1.0);
}

10、在顶点着色器中,我们可以使用inverse和transpose函数自己生成这个法线矩阵,这两个函数对所有类型矩阵都有效。注意我们还要把被处理过的矩阵强制转换为3×3矩阵,来保证它失去了位移属性以及能够乘以vec3的法向量。

Normal = mat3(transpose(inverse(model))) * aNormal;

因此我们需要一个在世界空间中的顶点位置。我们可以通过把顶点位置属性乘以模型矩阵(不是观察和投影矩阵)来把它变换到世界空间坐标。这个在顶点着色器中很容易完成,所以我们声明一个输出变量,并计算它的世界空间坐标:

out vec3 FragPos;  
out vec3 Normal;

void main()
{
    gl_Position = projection * view * model * vec4(aPos, 1.0);
    FragPos = vec3(model * vec4(aPos, 1.0));
    Normal = aNormal;
}

最后,在片段着色器中添加相应的输入变量。

in vec3 FragPos;

我们简单地使用摄像机对象的位置坐标代替(它当然就是观察者)。所以我们把另一个uniform添加到片段着色器,把相应的摄像机位置坐标传给片段着色器:

uniform vec3 viewPos;

11、NDC

 

4、模块

1、三角形

GLfloat vertices[] = {
		//position
		-0.5f, -0.5f, 0.0f,
		0.5f, -0.5f, 0.0f,
		0.0f, 0.5f, 0.0f,
	};

	//the date should be transfered to the memory on the Graphics Card,传到显存
	GLuint VAO, VBO;  //VAO:Vertex Array Object   VBO:Vertex Buffer Object传数据
	glGenVertexArrays(1, &VAO);  //创建 VAO
	glGenBuffers(1, &VBO);
	glBindVertexArray(VAO);  //设当前直线
	glBindBuffer(GL_ARRAY_BUFFER, VBO);  //VAO 和 VBO 成对出现
	// transfer the data:传数据
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);  //静态访问,几乎不修改
	//set the attribute
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,
		3 * sizeof(GLfloat), (GLvoid *)0);  //0:对应调色器里 location 的值;3:对应 vec3 三个量;GL_FLOAT:浮点型;GL_FALSE:;3*sizeof(GLfloat):对应 Buffer 里传的数据;(GLvoid*)0:从第 0 个位置开始
	glEnableVertexAttribArray(0);
	//glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE,
		//6 * sizeof(GLfloat), (GLvoid *)(3 * sizeof(GLfloat)));  //1:对应调色器里 color 的值;3:对应 vec3 三个量;GL_FLOAT:浮点型;GL_FALSE:;6*sizeof(GLfloat):每次跨越 6 个;(GLvoid*) (3 * sizeof(GLfloat)):从第 0 个位置开始
	//glEnableVertexAttribArray(1);

	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glBindVertexArray(0);

//glUseProgram(shaderProgram);  //使用调色器,不注释
		ourShader.Use();

		//Draw the triangle
		glBindVertexArray(VAO);  //使用 VAO,直接绑定
		glDrawArrays(GL_TRIANGLES, 0, 3);  //画三角形,从第 0 个数据开始画,到最后一个数据(第 3 个)结束
		glBindVertexArray(0);

2、两个VB0,VA0

float vertices[] = {
        // first triangle
        -0.9f, -0.5f, 0.0f,  // left 
        -0.0f, -0.5f, 0.0f,  // right
        -0.45f, 0.5f, 0.0f,  // top 
        // second triangle
         0.0f, -0.5f, 0.0f,  // left
         0.9f, -0.5f, 0.0f,  // right
         0.45f, 0.5f, 0.0f   // top 
    }; 

    unsigned int VBO, VAO;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glBindVertexArray(VAO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, 0); 
    glBindVertexArray(0); 

     glUseProgram(shaderProgram);
        glBindVertexArray(VAO); // seeing as we only have a single VAO there's no need to         bind it every time, but we'll do so to keep things a bit more organized
        glDrawArrays(GL_TRIANGLES, 0, 6); 

3、正方形

GLfloat vertices[] = {
		//first triangle
		0.5f, 0.5f, 0.0f,  //top right
		0.5f, -0.5f, 0.0f,  //bottom right
		-0.5f, -0.5f, 0.0f,  //top left
		-0.5f, 0.5f, 0.0f
	};
	unsigned int indices[] = {
		0,1,3,
		1,2,3
	};

	//the date should be transfered to the memory on the Graphics Card, 传到显存
	GLuint VAO, VBO;  //VAO:Vertex Array Object   VBO:Vertex Buffer Object 传数据
	 glGenVertexArrays(1, &VAO);  // 创建 VAO
	glGenBuffers(1, &VBO);
	glBindVertexArray(VAO);  // 设当前直线
	 glBindBuffer(GL_ARRAY_BUFFER, VBO);  //VAO 和 VBO 成对出现
	 // transfer the data:传数据
	 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);  // 静态访问,几乎不修改
	 //set the attribute
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,
		3 * sizeof(GLfloat), (GLvoid *)0);  //0: 对应调色器里 location 的值;3: 对应 vec3 三个量;GL_FLOAT: 浮点型;GL_FALSE:;3*sizeof(GLfloat): 对应 Buffer 里传的数据;(GLvoid*)0: 从第 0 个位置开始
	 //glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,
		//6 * sizeof(GLfloat), (GLvoid *)0);  //0: 对应调色器里 location 的值;3: 对应 vec3 三个量;GL_FLOAT: 浮点型;GL_FALSE:;3*sizeof(GLfloat): 对应 Buffer 里传的数据;(GLvoid*)0: 从第 0 个位置开始
	 glEnableVertexAttribArray(0);
	//glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE,
		//6 * sizeof(GLfloat), (GLvoid *)(3 * sizeof(GLfloat)));  //1: 对应调色器里 color 的值;3: 对应 vec3 三个量;GL_FLOAT: 浮点型;GL_FALSE:;6*sizeof(GLfloat): 每次跨越 6 个;(GLvoid*) (3 * sizeof(GLfloat)): 从第 0 个位置开始
	 //glEnableVertexAttribArray(1);


	//transfer the index
	GLuint EBO;
	glGenBuffers(1, &EBO);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);


	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glBindVertexArray(0);

ourShader.Use();

		//Draw the triangle
		glBindVertexArray(VAO);  // 使用 VAO,直接绑定

		 //glDrawArrays(GL_TRIANGLES, 0, 3);  // 画三角形,从第 0 个数据开始画,到最后一个数据(第 3 个)结束
		 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
		glBindVertexArray(0);

4、贴纹理给正方形

GLuint texture;  // 生成纹理
	 int width, height;

	glGenTextures(1, &texture);  // 生成
	 glBindTexture(GL_TEXTURE_2D, texture); // 绑定 2D 纹理

	 // 二维: S T   三维: S T R
	//i: 整型    f: 浮点型
	 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);  //FILTER: 滤波器
	 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);  //GL_NEAREST: 选取靠的最近的点, 关注点清晰度可以, 但边缘会模糊   GL_LINEAR: 整体看效果稍微模糊

	 unsigned char* image = SOIL_load_image("2.jpg", 
		&width, &height, 0, SOIL_LOAD_RGBA);  // 读取它的 RGBA 信息

	 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, 
		GL_UNSIGNED_BYTE, image);  // 专门贴纹理, 指定传多大的文件空间, 第一个 0 表示第 0 层, 按照 RGBA 的顺序, 第二个 0 不用管, 存成 unsigned_byte 的格式
	 glGenerateMipmap(GL_TEXTURE_2D);  //Mipmap: 图片金字塔
	 glBindTexture(GL_TEXTURE_2D, 0);

ourShader.Use();

		glActiveTexture(GL_TEXTURE0);  // 第 0 个位置, 对应的就是 frag 里面的 uniform, 运行过程中传
		 glBindTexture(GL_TEXTURE_2D, texture);  // 需要
		 glUniform1i(glGetUniformLocation(ourShader.Program, "ourTexture0"), 0);  // 对应 frag 里面的 ourTexture0, 在 Program 中找 ourTexture0
		//Draw the triangle
		glBindVertexArray(VAO);  // 使用 VAO,直接绑定

	
		//glDrawArrays(GL_TRIANGLES, 0, 3);  // 画三角形,从第 0 个数据开始画,到最后一个数据(第 3 个)结束
		 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // 解绑定
		 glBindVertexArray(0);

glDeleteTextures(1, &texture);

5、变换、正方体

变换

ourShader.Use();
		//glm 从 0.9.9 版本起,默认会将矩阵类型初始化为一个零矩阵(所有元素均为 0)
		glm::mat4 transform = glm::mat4(1.0f);  //初始化 4 * 4 单位矩阵

		//glm::vec3(1.0f, 1.0f, 1.0f),分别绕 x 轴、y 轴、z 轴进行旋转,如果都为 1.0f,就是绕和向量 (1,1,1) 转
		transform = glm::rotate(transform, glm::radians(20.0f) * static_cast(glfwGetTime()), glm::vec3(1.0f, 1.0f, 1.0f));

		//缩放,x、y、z 都缩放到原来的 0.5 倍
		transform = glm::scale(transform, glm::vec3(0.5f, 0.5f, 0.5f));

		GLuint transLoc = glGetUniformLocation(ourShader.Program, "transform"); 
		glBindVertexArray(VAO);  //使用 VAO,直接绑定

		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
		//glDrawArrays(GL_TRIANGLES, 0, 3);  //画三角形,从第 0 个数据开始画,到最后一个数据(第 3 个)结束
		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //解绑定
		glBindVertexArray(0);

正方体

glEnable(GL_DEPTH_TEST);  //深度测试
glDepthFunc(GL_LESS);  //深度信息小于当期信息,就把进行测试

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glDrawArrays(GL_TRIANGLES, 0, 36);  //画三角形,从第 0 个数据开始画,到最后一个数据(第 3 个)结束

6、鼠标键盘控制正方体


//键盘回应
void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mode);
//监听鼠标移动事件:xPos 和 yPos 代表当前鼠标位置
void MouseCallback(GLFWwindow *window, double xPos, double yPos);
//键盘移动
void ScrollCallback(GLFWwindow* window, double xoffset, double yoffset);

void DoMovement();

//初始化一个相机
Camera camera(glm::vec3(0.0f, 0.0f, 2.0f));
//设置初始量
GLfloat lastX = WIDTH / 2.0;
GLfloat lastY = HEIGHT / 2.0;
bool firstMouse = true;
double fov = 45.0;
//鼠标缩放
//double fov = 45.0;

bool keys[1024];  //存放获取的所有键盘操作,先存下来再进行操作

GLfloat deltaTime = 0.0f;  //两帧之间的间隔时间
GLfloat lastTime = 0.0f;  //上一帧绘制的时间


glfwSetKeyCallback(window, KeyCallback);
	//mouse_callback 是响应鼠标消息的回调函数,鼠标一移动 MouseCallback 函数就会被调用
	glfwSetCursorPosCallback(window, MouseCallback);
	//注册鼠标滚轮的回调函数
	 glfwSetScrollCallback(window, ScrollCallback);
	glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);  //不允许光标出现


	glm::mat4 view = glm::mat4(1.0f);  //初始化 4 * 4 单位矩阵


GLfloat currentFrame = glfwGetTime();  //屏幕刚画出来的时间
		deltaTime = currentFrame - lastTime;  //更新两帧之间的间隔时间
		lastTime = currentFrame;  //更新上一帧绘制的时间
		glfwPollEvents();  //把所有事件系统都取过来:键盘/鼠标等操作
		DoMovement();  //获取完操作之后的额外参数
		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);  //窗口背景颜色,RGB,最后一个是透明度
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //清除颜色缓冲,否则会保留之前的移动轨迹颜色
		//Bind the shader
		ourShader.Use();

		glm::mat4 model = glm::mat4(1.0f);  //model
		model = glm::rotate(model, glm::radians(20.0f) * static_cast
			(glfwGetTime()), glm::vec3(1.0f, 1.0f, 1.0f));

		view = camera.GetViewMatrix();  //获得相机矩阵
		glm::mat4 projection = glm::perspective(glm::radians((float)fov), 
(float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);

		//将矩阵传入着色器
		GLuint modelLoc = glGetUniformLocation(ourShader.Program, "model");  //到 vs 找到那个 model 变量
		GLuint viewLoc = glGetUniformLocation(ourShader.Program, "view");  //到 vs 找到那个 view 变量
		GLuint projectionLoc = glGetUniformLocation(ourShader.Program, "projection");  //到 vs 找到那个 projection 变量
		
		//最后:直接给出 model 矩阵数组,这里我们要把矩阵转换成数组的格式传递。
		glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
		glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
		glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection));

		//Draw the triangle
		glBindVertexArray(VAO);  //使用 VAO,直接绑定

		glDrawArrays(GL_TRIANGLES, 0, 36);  //画三角形,总共有 36 个顶点
		//glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
		glBindVertexArray(0);


void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mode)
{
	if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
		glfwSetWindowShouldClose(window, GL_TRUE);  //设定关闭窗口
	}

	if (key >= 0 && key < 1024) {
		if (action == GLFW_PRESS)
		{
			keys[key] = true;  //键盘按下去了,就设置为 true,即为1
		}
		else if (action == GLFW_RELEASE)
		{
			keys[key] = false;  //键盘松开,设为 false
		}
	}
}

void MouseCallback(GLFWwindow *window, double xPos, double yPos)
{
	if (firstMouse) {  //只有第一次才把鼠标的初始位置更新为 xPos 和 yPos 值
		lastX = xPos;
		lastY = yPos;
		firstMouse = false;
	}
	GLfloat xOffset = xPos - lastX;  //当前位置 - 上一个x
	GLfloat yOffset = lastY - yPos;  //注意这里是相反的,因为 y 坐标是从底部往顶部依次增大的

	lastX = xPos;
	lastY = yPos;

	camera.ProcessMouseMovement(xOffset, yOffset);
}


void ScrollCallback(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;
}


void DoMovement()
{
	if (keys[GLFW_KEY_W] || keys[GLFW_KEY_UP]) {  //W 或者 ↑
		camera.ProcessKeyboard(FORWARD, deltaTime);
	}
	if (keys[GLFW_KEY_S] || keys[GLFW_KEY_DOWN]) {
		camera.ProcessKeyboard(BACKWARD, deltaTime);
	}
	if (keys[GLFW_KEY_A] || keys[GLFW_KEY_LEFT]) {
		camera.ProcessKeyboard(LEFT, deltaTime);
	}
	if (keys[GLFW_KEY_D] || keys[GLFW_KEY_RIGHT]) {
		camera.ProcessKeyboard(RIGHT, deltaTime);
	}
}


7、光照

1、生成灯的对象

 Light lightModel = Light();

2、设置灯位置并变换

// 设置光源坐标
glm::vec3 lightPos(1.2f, 1.0f, 2.0f);
//旋转角度为 0.01f
		lightPos = glm::rotate(lightPos, 0.01f, glm::vec3(1.0f, 1.0f, 0.0f));

3、调用着色器

// 光源调色器
	Shader lightShader = Shader("light.vs", "light.frag");

4、渲染

// 画光源
		lightShader.Use();
		// 设置模型、视图和投影矩阵 uniform
		modelLoc = glGetUniformLocation(lightShader.Program, "model");  //到 vs 找到那个 model 变量
		viewLoc = glGetUniformLocation(lightShader.Program, "view");  //到 vs 找到那个 view 变量
		projectionLoc = glGetUniformLocation(lightShader.Program, "projection");  //到 vs 找到那个 projection 变量
		// 对模型进行操作
		model = glm::translate(model, lightPos);  //平移光源
		model = glm::scale(model, glm::vec3(0.2f));  //缩放光源

		// 传入数据
		glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
		glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
		glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection));
		lightColorLoc = glGetUniformLocation(lightShader.Program, "lightColor");
		glUniform3f(lightColorLoc, 1.0f, 1.0f, 1.0f);
lightModel.Draw(lightShader);

8、导入模型

​
// Setup and compile our shaders
	Shader shader("../res/model/model_loading.vs", "../res/model/model_loading.frag");

	// Load models
	Model ourModel((GLchar *)"../res/nanosuit/nanosuit.obj");

​
shader.Use();   // <-- Don't forget this one!
		// Transformation matrices
		glm::mat4 projection = glm::perspective(camera.GetZoom(), (float)screenWidth / (float)screenHeight, 0.1f, 100.0f);
		glm::mat4 view = camera.GetViewMatrix();
		glUniformMatrix4fv(glGetUniformLocation(shader.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
		glUniformMatrix4fv(glGetUniformLocation(shader.Program, "view"), 1, GL_FALSE, glm::value_ptr(view));

		// Draw the loaded model
		glm::mat4 model;
		model = glm::translate(model, glm::vec3(0.0f, -1.75f, 0.0f)); // Translate it down a bit so it's at the center of the scene
		model = glm::scale(model, glm::vec3(0.2f, 0.2f, 0.2f));	// It's a bit too big for our scene, so scale it down
		glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model));
		ourModel.Draw(shader);

注意,参考我这一篇博客可以获取相应模块的着色器

参考文献:

我的之前博客

https://mp.csdn.net/postedit/102980493

你可能感兴趣的:(计算机图像学,opengl,计算机图像学,汇总,南邮)