Add comments in blog posts on GitHub Pages websites
Add comments in blog posts on GitHub Pages websites
1 |
|
注意边界问题
quick_sort(q,l,j);
quick_sort(q,j+1,r);//此时x不能取q[r]
可以更改为
quick_sort(q,l,i-1);
quick_sort(q,i,r);//此时x不能取q[l]
1 |
|
1 | bool check(int x) {/* ... */} // 检查x是否满足某种性质 |
给定一个按照升序排列的长度为 n 的整数数组,以及 q 个查询。
对于每个查询,返回一个元素 k 的起始位置和终止位置(位置从 00 开始计数)。
如果数组中不存在该元素,则返回 -1 -1。
输入格式
第一行包含整数 n 和 q,表示数组长度和询问个数。
第二行包含 n 个整数(均在 1∼100001∼10000 范围内),表示完整数组。
接下来 q 行,每行包含一个整数 k,表示一个询问元素。
输出格式
共 q 行,每行包含两个整数,表示所求元素的起始位置和终止位置。
如果数组中不存在该元素,则返回 -1 -1。
数据范围
1≤n≤100000
1≤q≤10000
1≤k≤10000
输入样例:
1 | 6 3 |
输出样例:
1 | 3 4 |
答案
1 |
|
不考虑边界问题更简单
给定一个浮点数 n,求它的三次方根。
输入格式
共一行,包含一个浮点数 n。
输出格式
共一行,包含一个浮点数,表示问题的解。
注意,结果保留 66 位小数。
数据范围
−10000≤n≤10000
输入样例:
1 | 1000.00 |
输出样例:
1 | 10.000000 |
答案:
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
S[i] = S[i-1] + a[i]ans = S[r] - S[l-1]1 |
|
S[i][j] =a[i][j] + S[i][j-1] + S[i-1][j] - S[i-1][j-1]ans = S[x2][y2] - S[x1-1][y2] - S[x2][y1-1] + S[x1-1][y1-1]1 |
|
输入一个长度为 n 的整数序列。
接下来输入 m个操作,每个操作包含三个整数 l,r,c,表示将序列中 [l,r] 之间的每个数加上 c。
请你输出进行完所有操作后的序列。
前缀和的逆运算
构造 等同于 操作(i,i,a[i])
操作等价于
b[l] += c;1 |
|
输入一个 n 行 m列的整数矩阵,再输入 q 个操作,每个操作包含五个整数 x1,y1,x2,y2,c
其中 (x1,y1)和 (x2,y2)表示一个子矩阵的左上角坐标和右下角坐标。
每个操作都要将选中的子矩阵中的每个元素的值加上 c
请你将进行完所有操作后的矩阵输出。
操作等价于
b[x1][y1] += cb[x2+1][y1] -= cb[x1][y2+1] -= cb[x2+1][y2+1] += c1 |
|
基本模版
1 | for(i = 0,j = 0;i < n;i++){ |
核心思想
将O(n^2^)算法优化到O(n)
给定一个长度为 n 的整数序列,请找出最长的不包含重复的数的连续区间,输出它的长度。
输入格式
第一行包含整数 n。
第二行包含 n 个整数(均在 0∼1050∼105 范围内),表示整数序列。
输出格式
共一行,包含一个整数,表示最长的不包含重复的数的连续区间的长度。
数据范围
1≤n≤105
code
1 |
|
给定两个==升序排序==的有序数组 A 和 B,以及一个目标值 x。
数组下标从 0 开始。
请你求出满足 A[i]+B[j]=x 的数对 (i,j)。
数据保证有唯一解。
输入格式
第一行包含三个整数 n,m,x ,分别表示 A 的长度,B 的长度以及目标值 x
第二行包含 n 个整数,表示数组 A
第三行包含 m 个整数,表示数组 B
输出格式
共一行,包含两个整数 i 和 j
数据范围
数组长度不超过 10^5^
同一数组内元素各不相同。
1 ≤ 数组元素 ≤ 10^9^
code
1 |
|
n的二进制表示中的第k位是几?
1 | int n = 10; |
lowbit(x) 返回x的最后一位1
x & -x = x & (~x + 1)
eg:
x = 1010……..==1==000……0x = 0101……..==0==111……1x + 1) = 0000……..==1==000……0
~x + 1 = 0101……..==1==000……0
x & (
1 | int x; |
给定一个长度为 n 的数列,请你求出数列中每个数的二进制表示中 1 的个数。
code
1 |
|
1 | vector<int> alls; // 存储所有待离散化的值 |
假定有一个无限长的数轴,数轴上每个坐标上的数都是 0
现在,我们首先进行 n 次操作,每次操作将某一位置 x 上的数加 c
接下来,进行 m 次询问,每个询问包含两个整数 l 和 r,你需要求出在区间 [l,r] 之间的所有数的和
输入格式
第一行包含两个整数 n 和 m
接下来 n 行,每行包含两个整数 x 和
再接下来 m 行,每行包含两个整数 l 和 r
输出格式
共 m 行,每行输出一个询问中所求的区间内数字和。
数据范围
−10^9^≤x≤10^9^,
1≤n,m≤10^5^
−10^9^≤l≤r≤10^9^
−10000≤c≤10000
code
1 |
|
注意:
vector<int> alls 中存的是需要离散化的下标
const int N = 300010; 查询最多10^5^次,插入最多10^5^次,最多需要离散化2*查询+插入 = 3*10^5^次
实现unique函数
1 | vector<int>::iterator unique(vector<int> &a) |
alls.erase(unique(alls.begin(), alls.end()),alls.end());改为
alls.erase(unique(alls),alls.end());
1 | // 将所有存在交集的区间合并 |
给定 n 个区间 [li,ri],要求合并所有有交集的区间。
注意如果在端点处相交,也算有交集。
输出合并完成后的区间个数。
Eg. [1,3] & [2,6] -> [1,6]
输入格式
第一行包含整数 n。
接下来 n 行,每行包含两个整数 l 和 r。
输出格式
共一行,包含一个整数,表示合并区间完成后的区间个数。
数据范围
1 ≤ n ≤ 100000
−10^9^ ≤ li ≤ ri ≤ 10^9^
code
1 |
|
笔试中一般不采用动态链表
实现一个单链表,链表初始为空,支持三种操作:
现在要对该链表进行 M 次操作,进行完所有操作后,从头到尾输出整个链表。
注意: 题目中第 k 个插入的数并不是指当前链表的第 k 个数。例如操作过程中一共插入了 n 个数,则按照插入的时间顺序,这 n 个数依次为:第 1 个插入的数,第 2 个插入的数,…第 n 个插入的数。
输入格式
第一行包含整数 M,表示操作次数。
接下来 M 行,每行包含一个操作命令,操作命令可能为以下几种:
H x,表示向链表头插入一个数 x。D k,表示删除第 k 个插入的数后面的数(当 k 为 0 时,表示删除头结点)。I k x,表示在第 k 个插入的数后面插入一个数 x(此操作中 k 均大于 00)。输出格式
共一行,将整个链表从头到尾输出。
code
1 |
|
1 | // e[]表示节点的值,l[]表示节点的左指针,r[]表示节点的右指针,idx表示当前用到了哪个节点 |
实现一个双链表,双链表初始为空,支持 55 种操作:
现在要对该链表进行 M 次操作,进行完所有操作后,从左到右输出整个链表。
注意:题目中第 k 个插入的数并不是指当前链表的第 k 个数。例如操作过程中一共插入了 n 个数,则按照插入的时间顺序,这 n 个数依次为:第 1 个插入的数,第 2 个插入的数,…第 n 个插入的数。
输入格式
第一行包含整数 M,表示操作次数。
接下来 M 行,每行包含一个操作命令,操作命令可能为以下几种:
L x,表示在链表的最左端插入数 x。R x,表示在链表的最右端插入数 x。D k,表示将第 k 个插入的数删除。IL k x,表示在第 k 个插入的数左侧插入一个数。IR k x,表示在第 k 个插入的数右侧插入一个数。输出格式
共一行,将整个链表从左到右输出。
数据范围
1 ≤ M ≤ 100000
所有操作保证合法。
code
1 |
|
code
1 |
|
队尾插入,队头推出
code
1 |
|
给定一个长度为 N 的整数数列,输出每个数左边第一个比它小的数,如果不存在则输出 −1。
输入格式
第一行包含整数 N,表示数列长度。
第二行包含 N 个整数,表示整数数列。
输出格式
共一行,包含 N 个整数,其中第 i 个数表示第 i 个数的左边第一个比它小的数,如果不存在则输出 −1。
数据范围
1 ≤ N ≤ 10^5^
1 ≤ 数列中元素 ≤ 10^9^
样例
3 4 2 7 5
-1 3 -1 2 2
code
1 |
|
给定一个大小为 n≤10^6^ 的数组。
有一个大小为 k 的滑动窗口,它从数组的最左边移动到最右边。
你只能在窗口中看到 k 个数字。
每次滑动窗口向右移动一个位置。
以下是一个例子:
该数组为 [1 3 -1 -3 5 3 6 7],k 为 3。
| 窗口位置 | 最小值 | 最大值 |
|---|---|---|
| [1 3 -1] -3 5 3 6 7 | -1 | 3 |
| 1 [3 -1 -3] 5 3 6 7 | -3 | 3 |
| 1 3 [-1 -3 5] 3 6 7 | -3 | 5 |
| 1 3 -1 [-3 5 3] 6 7 | -3 | 5 |
| 1 3 -1 -3 [5 3 6] 7 | 3 | 6 |
| 1 3 -1 -3 5 [3 6 7] | 3 | 7 |
你的任务是确定滑动窗口位于每个位置时,窗口中的最大值和最小值。
输入格式
输入包含两行。
第一行包含两个整数 n 和 k,分别代表数组长度和滑动窗口的长度。
第二行有 n 个整数,代表数组的具体数值。
同行数据之间用空格隔开。
输出格式
输出包含两个。
第一行输出,从左至右,每个位置滑动窗口中的最小值。
第二行输出,从左至右,每个位置滑动窗口中的最大值。
输入样例:
1 | 8 3 |
输出样例:
1 | -1 -3 -3 -3 3 3 |
code
1 |
|
理解

init() : tt = -1, hh = 0; // 此时hh>tt 队空
窗口应该在(i-k+1)到i范围内
q[hh] ≥ i - k + 1(i-k+1)到i范围内 ,如果==队尾下标对应值比i下标对应值还要大==就丢弃(此时是以(i-k+1)到i为窗口范围,但实际i还未入队)q[++tt] = i;Leetcode
本文为计算机图形学作业2报告, 为本人计算机图形学课程作业, 仅供参考, 未经允许不得转载, 抄袭.
内容应包含但不局限于项目名称,项目简介。篇幅占整体内容的10%
本次作业在第一次作业的基础上,增加一个bezier曲面,并对场景添加光照和纹理效果。具体要求如下:
以bezier曲面模拟一面旗帜,曲面至少包含5*5个控制点;
在场景中使用phong光照模型来得到合理的光照效果;
对场景中的模型添加纹理贴图, 图片自行选择,不同类型的模型采用不同的贴图。
编程环境
MacOS,C++11,IDE: CLion,cmake,使用OpenGL,Glad,GLFW3.3.8,glm0.9.9.1
文件结构
1 | (base) alanzeng@AlandeMacBook-Pro CGA2 % tree |
在这一部分需要描述你的项目实现过程中用了哪些算法,需要你从算法背后的原理入手结合自己的项目进行描述,切忌段落式的粘贴代码,如果是自己写的算法,进行适当的算法复杂度分析。
示例:a) Lambert 漫反射光照模型 b) 正投影相机 c) Phong光照模型 d) 一些图形的绘制举例 e) 碰撞测试特例算法
注:一定要结合自己的项目去写这一部分,落到实处,切忌直接从网上直接粘贴理论知识。
Phong光照模型是计算三维计算机图形中光照效果的经典方法之一,它被广泛用于渲染三维场景和物体。Phong光照模型考虑了三种主要的光照成分:环境光、漫反射光和镜面光。
环境光(Ambient Light): 环境光是物体表面上的均匀光照,不依赖于光源的方向。它用于模拟场景中光源以外的间接光照明。环境光通常是一个常数,用来表示整体光照的强度。
漫反射光(Diffuse Light): 漫反射光是光线以角度入射到物体表面并均匀反射的光。它依赖于光线入射角和物体表面的法线(法向量),这个成分使物体的表面看起来具有粗糙的外观。漫反射光的强度在表面上不均匀,取决于入射角度和法向量之间的夹角。
镜面光(Specular Light): 镜面光是光线以特定角度入射到物体表面并以同样的角度反射的光,类似于镜面反射。这个成分使物体的表面看起来光滑,具有高光亮度。镜面光的强度取决于入射光线的方向、视线方向和物体的材质属性。
Phong光照模型可以表示为以下方程:
$$
I = k_a \cdot I_a + k_d \cdot I_d \cdot (N \cdot L) + k_s \cdot I_s \cdot (R \cdot V)^n
$$
其中:
在片段着色器中, 运用Phong光照模型进行计算
片段着色器中定义了Material(材质)和Light(光照)结构体
1 | struct Material { |
具体算法实现
1 | void main() |
贝塞尔曲面(Bezier Surface)是一种用于三维图形和计算机辅助设计(CAD)中的曲面表示方法。它是由法国工程师皮埃尔·贝塞尔(Pierre Bézier)于20世纪50年代发明的,并在汽车设计领域广泛应用。贝塞尔曲面由多个控制点定义,这些点控制了曲面的形状。它是一种常用的二次和三次曲面建模技术。ß
贝塞尔曲面的定义基于控制点和基函数。控制点是用来确定曲面的形状的点,而基函数是一种数学函数,它们根据控制点的位置来计算曲面上的点。一般来说,贝塞尔曲面是由两个参数u和v来定义的,这些参数的范围通常是从0到1。
一个常见的二次贝塞尔曲面可以用以下公式来表示:
$$
P(u, v) = (1-u)^2 * (1-v) * P0 + 2 * (1-u) * u * (1-v) * P1 + u^2 * (1-v) * P2\ + (1-u)^2 * v * P3 + 2 * (1-u) * u * v * P4 + u^2 * v * P5 +\ (1-u)^2 * (1-v)^2 * P6 + 2 * (1-u) * u * (1-v)^2 * P7 + u^2 * (1-v)^2 * P8
$$
其中,P0到P8是控制点的坐标,(u, v)是曲面上的点坐标。这个公式描述了如何根据控制点的位置以及参数u和v的值来计算曲面上的点。
贝塞尔曲面的优点之一是它在控制点的位置和权重上具有直观性,可以通过移动控制点来调整曲面的形状。此外,贝塞尔曲面是局部控制的,这意味着一个控制点的改变只会影响曲面上的局部区域。
在计算机图形中,贝塞尔曲面通常用于建模、渲染和处理复杂的曲面形状,例如汽车外壳、船体、飞机机身等。
本次实验中,我们要构建一个由$5\times5$控制点构成的贝塞尔曲面, 具体的实现请见2.3.3 BezierFace.h
纹理贴图是计算机图形学中强大且广泛应用的技术,它可以增强三维场景的真实感和视觉质量。不同类型的纹理和纹理技术可以用来模拟各种不同的视觉效果,从基本的颜色贴图到复杂的环境映射和法线贴图。
在本次实验中我们使用了stb_image库来加载贴图, 通过一下方法来具体实现纹理贴图
1 | unsigned int textureID; |
在这一部分,将自己的项目拆解成各个部分进行说明。切忌段落式的粘贴代码。
第二章应占整体篇幅的40%。
与上课时给出的shader.h代码相同
使用C++文件流读取着色器内容,储存到几个string对象里
以下实现了对着色器的编译和链接
1 | unsigned int vertex, fragment; |
定义了
1 | void use() const { glUseProgram(ID); } |
提供ProcessKeyboard, ProcessMouseMovement, ProcessMouseScroll方法,用于实现鼠标键盘控制
Camera 类 定义了位置,接收变化的变量,欧拉角,选项和构造函数,此外还有键盘鼠标操作函数和相机更新函数
1 | class Camera |
ProcessKeyboard处理从任何类似键盘的输入系统接收的输入
1 | void ProcessKeyboard(Camera_Movement direction, float deltaTime) |
ProcessMouseMovement处理从鼠标输入系统接收的输入。期望x和y方向上的偏移值。
1 | void ProcessMouseMovement(float xoffset, float yoffset, GLboolean constrainPitch = true) |
ProcessMouseScroll处理从鼠标滚轮事件接收的输入。只需要在垂直轮轴上输入
1 | void ProcessMouseScroll(float yoffset) |
updateCameraVectors
1 | void updateCameraVectors() |
定义类贝塞尔曲面类, 其中包含顶点个数, 索引个数, 顶点, 法线, 纹理, 索引, 控制点, 曲线阶数等等属性
1 |
|
1 | BezierFace::BezierFace(int step, float controlPoints[], int prec) |
该函数实现了Bezier曲面初始化
初始化参数
prec(precision):这个参数控制曲面的精度,它影响了生成的顶点密度。我们使用 (prec + 1) * (prec + 1) 个顶点和 prec * prec * 6 个索引。数据初始化
vertices、normals 和 texCoords,以及存储索引的容器 indices。这些容器将在后续的计算中使用。控制点
controlPoints 数组中。我们将这些控制点提取出来并存储在 controlPointsVector 容器中,以便后续计算使用。计算顶点
(i, j) 的参数空间,其中 i 和 j 分别表示沿 u 和 v 方向的参数值。对于每个 (i, j) 坐标点,我们使用贝塞尔曲面的公式计算了 x、y 和 z 坐标,并将它们存储在 vertices 中。计算法线和纹理坐标
texCoords 中。计算索引
为了定义Bezier曲面的三角形片元,我们使用了嵌套循环来计算索引。这些索引存储在 indices 中,以便在渲染时使用。
这个初始化过程将为Bezier曲面提供一个网格,其中包含离散的顶点、法线和纹理坐标,以及定义曲面几何的索引。在实验的后续部分,我们将使用这些数据来渲染Bezier曲面并展示其效果。
1 | void BezierFace::init(int prec) |
初始化函数中可以看到其中使用了Bernstein函数, 在Bezier曲线和Bezier曲面的计算中,Bernstein基函数(Bernstein basis functions)起着重要的作用。它们是一组多项式函数,用于确定Bezier曲线和曲面上的点的位置。
1 | float BezierFace::Bernstein(float t, int index) { |
具体实现和实验一中完全一致, 不再赘述
具体实现和实验一中完全一致, 不再赘述
主方法
Camera camera(glm::vec3(0.0f, 0.0f, 10.0f));Shader ourShader("../1.model_loading.vs", "../1.model_loading.fs");Model ourModel("../OBJ_Files/airboat.obj");#define STB_IMAGE_IMPLEMENTATION将stb_image.h编译为cpp文件使用1 |
定义函数, 和一些基本参数
1 | void mouse_callback(GLFWwindow* window, double xpos, double ypos); |
1 | // settings |
初始化, 加载窗口
这部分代码固定不变, 同时打开了深度检测
1 | // glfw: initialize and configure |
配置shader和model, 以及贝塞尔曲面的顶点和纹理信息
这里贴图采用了天津大学的校旗图案
1 | // build and compile shaders |
在循环中绘制图
其中为shader配置了参数, 因为单独添加Bezier曲面, Bezier曲面的信息单独在main函数中加载
1 | while (!glfwWindowShouldClose(window)) |
最后终止
1 | glfwTerminate(); |
对这些函数进行实现
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);
==void setUpVertices();==
==unsigned int loadTexture(char const* path);==
前五个函数处理键盘鼠标操作, 在实验一中有具体实现, 在此不再赘述, 此处展示setUpVertices()和loadTexture()方法, 用于实现Bezier曲面
1 | void setUpVertices() |
在这一部分,你可以对你的项目结果适当的进行截图展示和说明。
Bezier曲面, 贴图天津大学校旗图案展示
通过调整相机远近, 可以看到完整模型与Bezier曲面
同时可以通过键盘鼠标操作旋转视角
在这一部分,你需要对你在开发过程中遇到的一些困难进行描述和你是如何攻克的,在方法上和结果上展开叙述。
第三章占整体篇幅的30%。
在实现Bezier曲面时,我面临了一些挑战。首先,我需要考虑如何加载和处理控制点。Bezier曲面通常由控制点定义,因此我需要找到一种有效的方式来加载这些控制点。我采取了以下措施来解决这些问题:
整合Bezier曲面和实验一的困难:
整合Bezier曲面和实验一是另一个具有挑战性的任务。最初,我发现两者无法同时显示出来,这可能是因为没有正确地绑定和解绑VAO导致的。为了解决这个问题,我采取了以下措施:
VAO和渲染状态:我确保了解OpenGL渲染管线的工作方式,以及如何正确地绑定和解绑VAO。通过及时的绑定和解绑VAO,我成功地整合了Bezier曲面和实验一,使它们能够同时显示。
1 | glBindVertexArray(VAO); |
Shader程序:我确保两者之间的着色器程序设置和变量传递是正确的。在调试过程中,我检查了着色器程序是否编译和链接成功,并确保正确传递了变量和纹理。
OpenGL状态管理:我了解了OpenGL的状态管理,包括混合、深度测试、清除颜色缓冲等。在整合两者时,我确保了正确管理OpenGL状态,以避免不必要的问题。
坐标转换和变换:我也考虑到了物体的变换,如旋转、平移或缩放,以确保这些变换适用于Bezier曲面,使它们在同一坐标系中正确呈现。
通过逐步调试和测试,我克服了这些挑战,成功地将Bezier曲面整合到实验一中,以实现更复杂的图形应用程序。这个过程不仅增加了我的对OpenGL和图形编程的理解,还提高了我的解决问题和整合不同组件的能力。这一章的详细描述将有助于读者了解我在实验中面对的挑战以及我是如何成功应对它们。
课程收获,项目开发收获,课程建议等各个方面展开来叙述。内容上要有意义,量上要占整篇报告的10%左右。
在整个课程和项目开发过程中,我获得了许多宝贵的经验和知识,这些经验将对我产生深远的影响。以下是我在这个过程中的主要收获和一些建议:
课程收获:
项目开发收获:
课程建议:
总的来说,这门课程和项目开发经历为我提供了宝贵的机会,让我深入研究计算机图形学和图形编程。我相信我所获得的知识和技能将对我的学术和职业生涯产生长远的影响,同时也期待在未来的学术和职业发展中继续学习和成长。感谢这个精彩的学习经验!
本文为计算机图形学作业2报告, 为本人计算机图形学课程作业, 仅供参考, 未经允许不得转载, 抄袭.
本次项目完成作业1,实现了对obj文件的加载, 并对模型进行键盘和鼠标控制
具体实现如下:
编程环境
MacOS,C++11,IDE: CLion,cmake,使用OpenGL,Glad,GLFW3.3.8,glm0.9.9.1以及Assimp
文件结构
1 | Computer_Graphics_Assign1 |
在这一部分需要描述你的项目实现过程中用了哪些算法,需要你从算法背后的原理入手结合自己的项目进行描述,切忌段落式的粘贴代码,如果是自己写的算法,进行适当的算法复杂度分析。
示例:a) Lambert 漫反射光照模型 b) 正投影相机 c) Phong光照模型 d) 一些图形的绘制举例 e) 碰撞测试特例算法
注:一定要结合自己的项目去写这一部分,落到实处,切忌直接从网上直接粘贴理论知识。
首先是对于OBJ文件的加载,我使用了一个非常流行的模型导入库——Assimp
Assimp能够导入很多种不同的模型文件格式,它会将所有的模型数据加载至Assimp的通用数据结构中。当Assimp加载完模型之后,就能够从Assimp的数据结构中提取所需的所有数据。
详细思想和代码实现见Camera和Model_loading处
在这一部分,将自己的项目拆解成各个部分进行说明。切忌段落式的粘贴代码。
第二章应占整体篇幅的40%。
定义一个顶点结构体
1 | struct Vertex { |
定义网格类
构造函数导入导入数据,调用setupMesh()方法,在setupMesh()函数中初始化缓冲,并最终使用Draw()函数来绘制网格
构造函数
1 | Mesh(vector<Vertex> vertices, vector<unsigned int> indices) |
其中包含setupMesh()
1 | void setupMesh() |
以及提供Draw(),绘制每个mesh
1 | void Draw(Shader &shader) |
定义Model类
1 | class Model |
构造函数
其中包含了一个Mesh对象的vector,构造函数包含loadModel()函数和draw()函数
draw()函数遍历了所有网格,并调用它们各自的Draw函数
1 | void Draw(Shader shader) |
loadModel()函数,需要传入一个文件路径path,之后使用Assimp来加载模型至Assimp的一个叫做scene的数据结构中
1 |
|
之后调用processMesh()函数,这样就可以将从obj模型文件中加载出的数据处理到我设置的Mesh类中
1 | Mesh processMesh(aiMesh *mesh, const aiScene *scene) { |
与上课时给出的shader.h代码相同
使用C++文件流读取着色器内容,储存到几个string对象里
以下实现了对着色器的编译和链接
1 | unsigned int vertex, fragment; |
定义了
1 | void use() const { glUseProgram(ID); } |
提供ProcessKeyboard, ProcessMouseMovement, ProcessMouseScroll方法,用于实现鼠标键盘控制
Camera 类 定义了位置,接收变化的变量,欧拉角,选项和构造函数,此外还有键盘鼠标操作函数和相机更新函数
1 | class Camera |
ProcessKeyboard处理从任何类似键盘的输入系统接收的输入
1 | void ProcessKeyboard(Camera_Movement direction, float deltaTime) |
ProcessMouseMovement处理从鼠标输入系统接收的输入。期望x和y方向上的偏移值。
1 | void ProcessMouseMovement(float xoffset, float yoffset, GLboolean constrainPitch = true) |
ProcessMouseScroll处理从鼠标滚轮事件接收的输入。只需要在垂直轮轴上输入
1 | void ProcessMouseScroll(float yoffset) |
updateCameraVectors
1 | void updateCameraVectors() |
主方法
Camera camera(glm::vec3(0.0f, 0.0f, 10.0f));Shader ourShader("../1.model_loading.vs", "../1.model_loading.fs");Model ourModel("../OBJ_Files/airboat.obj");processInput (定义了键盘按键对应上下左右前后操作) 见processInput(GLFWwindow *window)
1 | void processInput(GLFWwindow *window) |
mouse_button_callback, mouse_callback, scroll_callback 实现了鼠标的操作
mouse_button_callback是检测鼠标点击左键右键时候对相机的更新操作
mouse_callback是检测到鼠标移动时对相机的更新操作
==这里定义了两个bool值来判断,只有在按压左键/右键时才对鼠标的移动进行处理==
1 | bool leftMouseButtonDown = false; |
鼠标滚轮
1 | void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) |
1 |
|
由于obj文件没有纹理和材质的信息,因此我加入了光照使得可以看清模型的立体结构
无光照效果如下
加入光照后效果如下
1 |
|
1 |
|
##### 向前
##### 向后
##### 向上
##### 旋转
其他具体操作见视频
在这一部分,你需要对你在开发过程中遇到的一些困难进行描述和你是如何攻克的,在方法上和结果上展开叙述。
第三章占整体篇幅的30%。
课程收获,项目开发收获,课程建议等各个方面展开来叙述。内容上要有意义,量上要占整篇报告的10%左右。