摄像机
观察空间,是以摄像机的视角作为场景原点时场景中所有的顶点坐标;要定义一个摄像机,需要它在世界空间中的位置、观察方向、指向它右侧的向量及指向它上方的向量。
1.摄像机位置
摄像机移动方向应与物体移动方向相反;
2.摄像机方向
摄像机方向向量指从它到目标向量的相反方向;
3.右轴
代表摄像机空间的x轴的正向;通过先定义一个上向量,将其与方向向量叉乘。即可得右向量。
4.上轴
将右向量和方向向量进行叉乘;
LookAt
若有三个相互垂直的轴定义了一个坐标空间,即可使用这三个轴加一个平移向量创建一个矩阵,该矩阵乘以任何向量可以将其变换到该坐标空间中;故可以创建LookAt矩阵:
其中R为右向量,U为上向量,D为方向向量,P为摄像机位置向量。
通过定义摄像机位置,目标位置和表示世界空间中的上向量的向量(用于计算右向量使用的上向量)即可计算LookAt矩阵。
自由移动
|
|
设置了相机位置,相机朝向和上方向之后,可以通过按键对相机位置进行修改,从而调整观察角度;
设置通过按键输入调整摄像机的位置;
欧拉角
- 俯仰角pitch:物体绕x轴转过的角度;
- 偏航角yaw:物体绕y轴转过的角度;
鼠标输入时,水平移动影响偏航角;竖直移动影响俯仰角;1234567891011121314151617181920212223242526272829303132bool firstMouse = true;float lastX = 400;float lastY = 300;static void PssiveMouseCB(int x, int y){if(firstMouse){lastX = x;lastY = y;firstMouse = false;}float xoffset = x - lastX;float yoffset = y - lastY;lastX = x;lastY = y;float sensitivity = 0.05f;xoffset *= sensitivity;yoffset *= sensitivity;yaw += xoffset;pitch += yoffset;if(pitch > 89.0f)pitch = 89.0f;if(pitch < -89.0f)pitch = -89.0f;vec3 front;front.x = cosf(radians(pitch)) * cosf(radians(yaw));front.y = sinf(radians(pitch));front.z = cosf(radians(pitch)) * sinf(radians(yaw));cameraFront = normalize(front);}
纹理
纹理坐标,与每个顶点关联,表示该从纹理图像的哪个部分采样,之后在图形的其他片段上进行片段插值;纹理坐标在x和y轴上,范围为0到1(2D纹理图像),纹理坐标起始于(0,0),即纹理图片的左下角,终于(1,1),即纹理图片的右上角。
纹理环绕方式
将纹理坐标设置在范围(0,1)之外,OpenGL的处理方式:
- GL_REPEAT:对纹理的默认行为,重复纹理图像;
- GL_MIRRORED_REPEAT:重复纹理图像,但每次重复图片是镜像放置的;
- GL_CLAMP_TO_EDGE:纹理坐标被约束在0到1之间,超出部分重复纹理坐标的边缘,产生一种边缘被拉伸的效果;
- GL_CLAMP_TO_BORDER:超出的坐标为用户指定的边缘颜色;
上述选项都可以使用glTexParameter*函数对单独的一个坐标轴设置:12glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
若选择GL_CLAMP_TO_BORDER选项,需要指定边缘的颜色:
纹理过滤
- 纹理坐标:给模型顶点设置的数组,OpenGL以该顶点的纹理坐标去查找纹理图像上的像素,然后进行采样提取纹理像素的颜色;
- 纹理像素:Texel,组成图片的像素点;
- 纹理过滤,用于将纹理像素映射到纹理坐标上;
- GL_NEAREST:近邻过滤,OpenGL选择中心点最接近纹理坐标的像素作为该坐标的颜色值;
- GL_LINEAR:线性过滤,基于纹理坐标附近的纹理像素,计算插值作为纹理坐标的像素值;
当进行放大和缩小时可以设置纹理过滤的选项,需要使用glTexParameter*函数为放大缩小指定过滤方式:12glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
多级渐远纹理(MipMap)
即一系列的纹理图像,后一个纹理图像是前一个的二分之一;距观察者的距离超过一定阈值时,OpenGL会使用不同的多级渐远纹理;
加载与创建纹理
1. stb_image.h
单头文件图像加载库,可以加载大部分流行的文件格式,并能简单的整合到工程中。将stb_image.h文件加入工程,并另创建一个新的C++文件,输入代码:
通过定义STB_IMAGE_IMPLEMENTATION,预处理器会修改头文件,让其只包含相关的函数定义源码,相当于将这个头文件变为一个.cpp文件。
函数读取图像文件;
函数输入生成纹理的数量,将其存在第二个参数的数组中(此处为单独的一个unsigned int),并绑定该纹理对象;
纹理通过glTexImage2D来生成,第一个参数指定了纹理目标;第二个参数为纹理指定多级渐远纹理的级别,0表示基本级别;第三个参数表示希望将纹理存储为何种格式;下个参数应始终设为0;第七第八个参数定义了源图的格式和数据类型;最后一个参数为图像数据;
调用glTexImage2D时,当前绑定的纹理对象会被附加上纹理图像,目前只有基本级别的纹理图像被加载,若要使用多级渐远纹理,必须手动设置所有不同的图像(不断递增第二个参数),或者直接在生成纹理之后调用glGenerateMipmap,这会为当前绑定的纹理自动生成所需要的多级渐远纹理。
释放图像的内存;
GLSL有一个供纹理对象使用的内奸数据类型,称为采样器,以纹理类型为后缀,可以简单声明一个uniform sampler*D把一个纹理添加到片段着色器中,之后将纹理赋值给该uniform。GLSL内建的texture函数来采样纹理的颜色,第一个参数是纹理采样器,第二个参数是对应的纹理坐标;texture函数会使用之前设置的纹理参数相应的颜色值进行采样,这个片段着色器的输出就是纹理的(插值)纹理坐标上的(过滤后的)颜色。
在调用glDrawElements之前绑定纹理,会自动把纹理赋值给片段着色器的采样器;
纹理单元
一个纹理的位置值通常称为一个纹理单元,一个纹理单元的默认纹理单元是0,是默认的激活纹理单元,故不需要使用glUniformi进行位置分配。
纹理单元的主要目的是在着色器中使用多于一个的纹理,通过把纹理单元赋值给采样器,可以一次绑定多个纹理,只要首先激活对应的纹理单元。
使用函数告知OpenGL每个着色器采样器属于哪个纹理单元,放在渲染循环之前进行;
在绑定纹理之前先激活纹理单元;