参考视频计算机图形学基础–OpenGL的实现_哔哩哔哩_bilibiliT
图形绘制
点
GL_POINTS
#define FREEGLUT_STATIC // Define a static library for calling functions
#include <GL/freeglut.h> // Include the header file
void myPoints() { //show three points in screen
glClear(GL_COLOR_BUFFER_BIT);
glPointSize(3);
glBegin(GL_POINTS); //show what to draw,here we draw points
glColor3f(1.0, 0.0, 0.0); //color:red
glVertex2i(-3, 3);//coordinate
glColor3f(0.0, 1.0, 0.0); //color:green
glVertex2i(10, 20);//coordinate
glColor3f(0.0, 0.0, 1.0); //color:blue
glVertex2i(0, -15);//coordinate
glEnd();
glFlush(); //把绘制的缓存推送到屏幕上
}
void init() {
glClearColor(1.0, 1.0, 1.0, 1.0); //black background
glMatrixMode(GL_PROJECTION);
glLoadIdentity;
gluOrtho2D(-100, 100, -100, 100); //可以显示的范围
}
int main(int argc, char* argv[]) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
glutInitWindowPosition(200, 300); //在屏幕中的位置
glutInitWindowSize(300, 300);
glutCreateWindow("Display Points");
init();
glutDisplayFunc(myPoints); //回调函数
glutMainLoop();
return 0;
}
结果:
注意:颜色改一次换一次(废话),如果不改的话那就一直一个颜色
glFlush()很重要!是把图片推送到屏幕上!
线段
GL_LINES
两个两个配对连线
void lines() {
int p1[] = { 6,4 };
int p2[] = { 1,1 };
int p3[] = { 3,7 };
int p4[] = { 5,1 };
int p5[] = { 0,4 };
glClear(GL_COLOR_BUFFER_BIT);//clear
glColor3f(0.3, 0.1, 0.8);
glPointSize(3);
glBegin(GL_LINES); //这个以及后面几个改的是这里
glVertex2iv(p1);
glVertex2iv(p2);
glVertex2iv(p3);
glVertex2iv(p4);
glVertex2iv(p5); //绘制两个线段是因为P5没有匹配的
glEnd();
glFlush();
}
GL_LINE
GL_LINE_LOOP
多边形 POLYGON
GL_POLYGON
void polygonTraingle() {
int p1[] = { 1,3 };
int p2[] = { 3,0 };
int p3[] = { 6,0 };
int p4[] = { 7,3 };
int p5[] = { 6,6 };
int p6[] = { 3,6 };
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0.6, 0.5, 0.2);
glPointSize(3);
glBegin(GL_POLYGON); //point first
glVertex2iv(p1);
glVertex2iv(p2);
glVertex2iv(p3);
glVertex2iv(p4);
glVertex2iv(p5);
glVertex2iv(p6);
glEnd();
glFlush();
}
结果
GL_TRIANGLES
GL_QUADS
键鼠交互
键盘
glutKeyboardFunc()
这里重点关注一下那个mykeyboard和mian中的glutkeyboardfuc()
#define FREEGLUT_STATIC // Define a static library for calling functions
#include <GL/freeglut.h> // Include the header file
int xd=0, yd = 0;
void myDisplay() {
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0.8,0.5,0.6);
glPointSize(5);
glBegin(GL_POLYGON);
glVertex2i(10 + xd,10 + yd);
glVertex2i(20 + xd,10 + yd);
glVertex2i(20 + xd,0 + yd);
glVertex2i(10 + xd,0 + yd);
glEnd();
glFlush();
}
void myKeyBoard(unsigned char key, int x, int y) {
switch (key) {
case 'w':yd++; break;
case 's':yd--; break;
case 'a':xd--; break;
case 'd':xd++; break;
}
glutPostRedisplay(); //要求重新绘制窗口的内容
}
void init() {
glClearColor(1.0, 1.0, 1.0, 1.0); //black background
glMatrixMode(GL_PROJECTION);
glLoadIdentity;
gluOrtho2D(-20, 30, -20, 30); //可以显示的范围
}
void main(int argc, char* argv[]) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
glutInitWindowPosition(300, 100); //在屏幕中的位置
glutInitWindowSize(600, 500);
glutCreateWindow("Key interaction");
init();
glutDisplayFunc(myDisplay); //回调函数
glutKeyboardFunc(myKeyBoard);
glutMainLoop();
}
效果
可爱粉色方坨坨会随着你的wasd键上下左右移动
鼠标
glutMouseFunc
重点关注一下mouseMotion函数
#define FREEGLUT_STATIC // Define a static library for calling functions
#include <GL/freeglut.h> // Include the header file
GLint xd=0, yd = 0; //GLint 主要用于在OpenGL中处理整数数据,用于配置和表示与图形渲染相关的各种参数和信息。
GLint w = 600, h = 500;
void myDisplay() {
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0.8, 0.5, 0.6);
glPointSize(5);
glBegin(GL_POLYGON);
glVertex2i(10 + xd, 10 + yd);
glVertex2i(20 + xd, 10 + yd);
glVertex2i(20 + xd, 0 + yd);
glVertex2i(10 + xd, 0 + yd);
glEnd();
glFlush();
}
void mouseMotion(GLint button,GLint state, GLint x,GLint y) { //鼠标的按钮,鼠标是按下还是弹起,x,y
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) { //鼠标左键并按下
xd = x;
yd = h-y;
glutPostRedisplay();
}
}
void init() {
glClearColor(1.0, 1.0, 1.0, 1.0); //black background
glMatrixMode(GL_PROJECTION);
glLoadIdentity;
gluOrtho2D(0, w, 0, h); //可以显示的范围
}
void main(int argc, char* argv[]) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
glutInitWindowPosition(300, 100); //在屏幕中的位置
glutInitWindowSize(w, h);
glutCreateWindow("Mouse Motion");
init();
glutDisplayFunc(myDisplay); //回调函数
glutMouseFunc(mouseMotion);
glutMainLoop();
}
结果
可爱粉色方坨坨会随着你的鼠标移动
图形变换
平移
x = x+tx
y = y+ty
这个挺简单的就不多写了
旋转
x,y
绕原点旋转θ
x' = xcosθ - ysinθ
y' = xsinθ + ycosθ
绕 xr yr旋转θ
x' = xr+ (x-xr)cosθ - (y-yr)sinθ
y' = yr + (x-xr)sinθ + (y-yr)cosθ
缩放
x' = x*Sx
y' = y*Sy
glPushMatrix()
glPushMatrix()
是OpenGL中的一个函数,它用于将当前的模型视图矩阵(Model-View Matrix)入栈,保存当前矩阵的副本。这个函数通常与 glPopMatrix()
配合使用。
glPushMatrix()
的主要作用是保存当前的变换状态,使您可以在以后的绘图操作中修改变换,然后使用 glPopMatrix()
恢复先前的变换状态。这对于在不同对象之间应用不同的变换或在绘制嵌套的对象时非常有用。
动画
glTimerFunc()
它是用于注册一个定时器回调函数的函数,以便在指定的时间间隔内执行某个操作。这个函数通常用于在OpenGL应用程序中实现动画、周期性更新或其他需要定时触发的任务。
下面是它的基本语法:
void glutTimerFunc(unsigned int millis, void (*callback)(int value), int value);
millis
:表示定时器回调函数应该在多少毫秒后执行。callback
:是一个函数指针,用于指定在定时器触发时要执行的回调函数。value
:是一个整数值,可以传递给回调函数,通常用于标识不同的定时器。
纹理贴图
-
glTexImage2D()
:- 作用: 定义图像作为纹理。
- 参数: 指定纹理的类型(2D、立方体映射等)、层级(用于纹理映射的不同细节级别)、颜色格式等。
- 记住使用前要先 glEnable(GL_TEXTURE_2D)
-
glTexParameter*()
:- 作用: 指定纹理的过滤和包装方式。
- 参数: 包括
GL_TEXTURE_MIN_FILTER
和GL_TEXTURE_MAG_FILTER
,它们分别用于设置纹理的缩小和放大过滤器,以及GL_TEXTURE_WRAP_S
和GL_TEXTURE_WRAP_T
,用于设置纹理坐标的包装方式。
-
glTexEnv{fi}[v]()
:- 作用: 指定纹理的作用方式,如调制、混合或贴图。
- 参数: 包括
GL_TEXTURE_ENV_MODE
,它定义了纹理的调色模式。
-
glTexCoord{1234}{sifd}{v}()
:- 作用: 指定纹理坐标。
- 参数: 设置纹理坐标的s、t、r、q分量,通常用于指定纹理坐标的位置。
-
glTexGen{ifd}[v]()
:- 作用: 由OpenGL自动生成纹理坐标。
- 参数: 指定生成纹理坐标的坐标和生成方式。
-
glHint()
:- 作用: 定义透视矫正提示。
- 参数: 指定透视矫正的提示,影响OpenGL在生成透视纹理时的精度和速度权衡。
-
glBindTexture()
:- 作用: 将一个命名的纹理绑定到纹理目标上。
- 参数: 指定目标纹理和要绑定的纹理对象。
- glHnit()
- 作用:用于渲染时的提示
参数: target
参数指定了要设置提示的目标,mode
参数指定了要设置的提示模式
glTexImage2D()
glTexImage2D(target, level, components, w, h, border, format, type, texels);
是一个用于指定二维纹理图像的OpenGL函数。下面是该函数的参数说明:
-
target
:指定纹理的类型,可以是以下之一:GL_TEXTURE_1D
:一维纹理GL_TEXTURE_2D
:二维纹理GL_TEXTURE_3D
:三维纹理GL_TEXTURE_CUBE_MAP_POSITIVE_X
到GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
:立方体贴图的六个面- 等等
-
level
:指定纹理的细节级别。0级是最详细的级别,级别逐渐增加,表示更低分辨率的版本。 -
components
:指定纹理的颜色分量数量,可以是以下之一:GL_RED
:红色分量GL_GREEN
:绿色分量GL_BLUE
:蓝色分量GL_ALPHA
:透明度分量GL_RGB
:RGB颜色GL_RGBA
:RGBA颜色
-
w
和h
:指定纹理图像的宽度和高度。 -
border
:指定边框的宽度,通常设置为0。 -
format
:指定texels
数据的格式,例如:GL_RED
GL_RG
GL_RGB
GL_RGBA
-
type
:指定texels
数据的数据类型,例如:GL_UNSIGNED_BYTE
:8位无符号整数GL_UNSIGNED_SHORT
:16位无符号整数GL_FLOAT
:32位浮点数
-
texels
:指定纹理图像的数据,是一个指向存储纹理数据的指针。
glTexParameteri()
1. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
2. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1这个函数调用是用于设置二维纹理对象的放大过滤器。下面是这个函数调用的各个参数的说明:
-
GL_TEXTURE_2D
:指定目标纹理为二维纹理。这是一个纹理目标,表示后续的操作将影响到绑定到GL_TEXTURE_2D
的纹理对象。 -
GL_TEXTURE_MAG_FILTER
:指定设置的过滤器是纹理的放大过滤器。 -
GL_NEAREST
:指定使用最近邻插值方法进行纹理的放大过滤。最近邻插值选择离采样点最近的纹理像素的颜色。
glTexXCoord() -- glVertex()
设置二维纹理坐标,并接受两个参数 s
和 t
,它们分别代表纹理坐标的水平(通常称为s坐标)和垂直(通常称为t坐标)分量。这些坐标通常在 [0, 1] 范围内,表示纹理上的相对位置。
glvertex是被映射的地方
显示
OpenGL的变换和投影矩阵
glViewport()
用于设置视口的函数。视口是一个矩形区域,用于确定OpenGL渲染的最终图像在屏幕上的位置和大小。
void glViewport(GLint x, GLint y, GLsizei width, GLsizei height);
x
和y
:指定视口在窗口中的左下角位置的坐标。width
和height
:指定视口的宽度和高度。
glViewport()
函数通常在OpenGL的初始化过程中被调用,用于设置视口的初始大小和位置。它定义了OpenGL渲染的最终图像将覆盖窗口的哪个部分。
glMatrixMode()
- 作用: 选择当前矩阵模式。
- 参数:
mode
可以是GL_MODELVIEW
、GL_PROJECTION
或GL_TEXTURE
中的一个,分别表示模型视图矩阵、投影矩阵或纹理矩阵。 - 示例:
glMatrixMode(GL_MODELVIEW);
选择模型视图矩阵。
glLoadIdentity()
- 作用: 将当前选择的矩阵重置为单位矩阵。
- 示例:
glLoadIdentity();
将当前选择的矩阵重置为单位矩阵,通常在开始新的绘制操作前调用。
gluOrtho2D()
- 作用: 设置二维正交投影矩阵。
- 参数:
left
、right
、bottom
、top
分别定义了裁剪空间的左、右、下、上边界。 - 示例:
gluOrtho2D(0, windowWidth, 0, windowHeight);
设置一个左上角在 (0, 0)、右下角在 (windowWidth, windowHeight) 的正交投影矩阵。
glOrtho()
- 作用: 设置三维正交投影矩阵。
- 参数:
left
、right
、bottom
、top
、near
、far
分别定义了裁剪空间的左、右、下、上、近裁剪面和远裁剪面的位置。 - 示例:
glOrtho(-1, 1, -1, 1, 0.1, 100);
设置一个在近裁剪面和远裁剪面之间的正交投影矩阵。
gluPerspective()
- 作用: 设置透视投影矩阵。
- 参数:
fovy
是垂直视野角度,aspect
是宽高比,zNear
和zFar
分别是近裁剪面和远裁剪面的距离。 - 示例:
gluPerspective(45, windowWidth / windowHeight, 0.1, 100);
设置一个透视投影矩阵,垂直视野角度为45度,宽高比为窗口宽高比。
glFrustum()
- 作用: 设置一个用于非对称的透视投影矩阵。
- 参数:
left
、right
、bottom
、top
、near
、far
分别定义了裁剪空间的左、右、下、上、近裁剪面和远裁剪面的位置。 - 示例:
glFrustum(-1, 1, -1, 1, 1, 100);
设置一个近裁剪面和远裁剪面之间的非对称透视投影矩阵。
去除隐藏表面
放在主函数的
glutInitDisplayMode()
指定了图形窗口的一些属性和特性,比如颜色模式、缓冲区属性等。在创建 GLUT 窗口之前调用这个函数是必要的。
放在初始化函数的
glEnable(GL_DEPTH_TEST)
- 作用: 启用深度测试。
- 解释: 深度测试是一种用于解决物体遮挡关系的技术。启用深度测试后,OpenGL 会在绘制每个像素时考虑深度值,只有深度值最小的像素才会被绘制,这样可以确保近物体遮挡远物体。
glClear(GL_COLOR_BUFFER_BIT |GL_DEPTH_BUFFER_BIT)
- 作用: 清除颜色缓冲区和深度缓冲区。
- 解释: 在每一帧渲染开始前,通常需要清除颜色缓冲区和深度缓冲区,以确保之前渲染的图像不会影响当前帧的渲染。
GL_COLOR_BUFFER_BIT
表示清除颜色缓冲区,GL_DEPTH_BUFFER_BIT
表示清除深度缓冲区。这个操作将使整个窗口的渲染目标变为空白状态。
backface removal 背面去除
glEnable(GL_CULL_FACE);
- 作用: 启用多边形的背面剔除。
- 解释: 背面剔除是一种优化技术,它通过检测多边形的法向量方向,剔除不可见的背面,从而提高渲染效率。启用之后,OpenGL 将不绘制被视为背面的多边形。
glCullFace(GLenum);
- 作用: 设置背面剔除时剔除的多边形方向。
- 参数:
mode
可以是GL_FRONT
、GL_BACK
或GL_FRONT_AND_BACK
中的一个,分别表示剔除正面、剔除背面或剔除正背两面。 - 解释: 这个函数定义了哪一侧的多边形应该被剔除。通常,你会选择剔除不会被观察者看到的一侧,以提高性能。例如,如果启用了背面剔除,并设置
glCullFace(GL_BACK)
,则只有背向观察者的多边形会被剔除。
depth buffer 函数
glClear(GL_DEPTH_BUFFER_BIT);
- 作用: 清除深度缓冲区。
- 解释: 这个函数用于在渲染新帧之前清除深度缓冲区。
GL_DEPTH_BUFFER_BIT
表示清除深度缓冲区。这是为了确保深度信息在渲染下一帧时是干净的。
glEnable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
启用/禁用深度测试
glClearDepth(maxDepth);
- 作用: 设置深度缓冲区的清除值。
- 参数:
maxDepth
是一个浮点数,表示深度缓冲区被清除时的深度值,默认是1.0。 - 解释: 这个函数可以用于设置深度缓冲区的初始值。在深度测试时,深度值的范围通常是从0.0(近裁剪面)到1.0(远裁剪面)。
glClearDepth(maxDepth)
可以用于设置清除深度缓冲区时使用的深度值,确保深度值在这个范围内。
调整裁剪平面
glDepthRange(nearNormDepth, farNormDepth);
glDepthFunc(testCondition);
glPolygonMode()
颜色
glClearColor()
void glClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
这个函数用于设置清除颜色缓冲区时的颜色
glClear()
函数来清除颜色缓冲区
glFlush()
/ glutSwapBuffers()
将图像显示到屏幕上。这样就能够在每一帧开始时确保背景颜色是清除后的颜色。