opengl-glut(内含总结的学习资源)

学习资料有:
1.Microsoft官方的opengl-glut文章,最全面,全英文,可作为字典查阅使用
2.博主xie_zi的opengl-glut专栏,通俗的文章
3.知乎的opengl-glut文章
3.opengl-glut文档
4.open-glfw/glad的文章

本文较长(其实主要是贴的代码比较长),可每天学一部分,结合专栏,官方网址学习,个人仅仅记个笔记,讲的并不深入,真正的理解还是需要多方面查资料一步步啃啊,一起努力把

单词学习

1.buffer   n./v. 缓冲,保护
2.flush    v.冲洗,脸红
3.vertex/vertice   n.顶点
4.render   v.绘制
5.display  v./n.陈列,展示
6。func/function n.函数
7.syntax  n.句法,语法
8.parameter n.界限,范围,参数,变量
9.modify   v.修改
10.projection n.估算,预测;投射,投影
                                   3.15

环境搭建

用vs安装OpenGL的glut的文章
头文件

#include <GL/glut.h>

opengl四个库

OpenGL的基本库(GL):  库文件:opengl32.lib,头文件:gl.h
OpenGL实用库(GLU):   库文件:glu32.lib,头文件:glu.h 
OpenGL Programming Guide辅助库(glaux): 库文件:glaux.lib,头文件:glaux.h 
OpenGL的工具库(glut): 库文件:glut32.lib,头文件:glut.h

**

opengl函数样式

在这里插入图片描述

**
OpenGL的函数在格式上很有特点,它以gl为前缀并且函数名的最后一个字母指出所用的数据类型,如:glColor3f(),字母f指明要使用浮点数。字母前的数字指明参数个数或指明二维还是三维,如: glVertex2f()是要设置二维的点。
glVertex2i()是设置int类型的二维的点

初始化-主函数部分

main函数几个组成部分

 int main()
 {
    glutInit(&argc, argv);                         //初始化
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);   // 显示模式
	glutInitWindowPosition(50, 100);   // 窗口位置
	glutInitWindowSize(400, 400);      //窗口大小
	glutCreateWindow("An Example OpenGL Program"); //开始创建
    init();//接下来讲
	glutDisplayFunc(f);       // 进入绘画,f为用于绘画的函数名
	glutMainLoop(); //保持窗口不消失
 return 0;
 }

(1)还有个init函数
glMatrixMode函数指定哪个矩阵是当前矩阵
gluOrtho2D定义二维正交投影矩阵

void init(void)
{
	glClearColor(1.0, 1.0, 1.0, 0.0);  // Set display-window color to white.
	glMatrixMode(GL_PROJECTION);       // Set projection parameters.
	gluOrtho2D(0.0, 200.0, 0.0, 150.0);//gluOrtho2D 函数定义二维正交投影矩阵。
}

(2)main其中的函数

Void glutInitDisplayMode(unsighed int mode)

参数:

Mode――可以指定下列显示模式

Mode参数是一个GLUT库里预定义的可能的布尔组合。你使用mode去指定颜色模式,数量和缓冲区类型。

指定颜色模式的预定义常量有:

1:GLUT_RGBA或者GLUT_RGB。指定一个RGBA窗口,这是一个默认的颜色模式。

2:GLUT_INDEX。指定颜色索引模式。

这个显示模式还允许你选择单缓冲区或双缓冲区窗口。

1:GLUT_SINGLE.单缓冲区窗口。

2:GLUT_BUFFER.双缓冲区窗口,这是产生流畅动画必须选的。

还可以指定更多,如果你想指定一组特殊的缓冲的话,用下面的变量:

1:GLUT_ACCUM.累积缓冲区。

2:GLUT_STENCIL.模板缓冲区。

3:GLUT_DEPTH.深度缓冲区。

 

假定你想要一个有单缓冲区,深度缓冲区的RGB窗口
你用“或“(|)操作符来建立你想要的显示模式。

…………….

glutInitDisplayMode(GLUT_RGB|GLUT_SINGLE|GLUT|DEPTH);

…………….

名词解释

在这里插入图片描述

(1)颜色缓冲区、深度缓冲区、模板缓冲区和累积缓冲区
(2)opengl深度缓冲,深度测试

opengl基本图形绘制

相关博客:
opengl函数详解

用到的函数有:
   glClear//清除颜色缓冲区
   glColor3f//设置颜色
   glBegin//开始绘制
   glEnd//结束绘制
一个例子:
void f (void)
{
    glClear (GL_COLOR_BUFFER_BIT);  // Clear display window.清除颜色缓冲区
    glColor3f (0.0, 0.0, 1.0);      // Set line segment color to red.设置颜色
    glBegin (GL_LINES);
        glVertex2i (180, 15);       // Specify line-segment geometry.
        glVertex2i (10, 145);
    glEnd ( );
    glFlush ( );     // Process all OpenGL routines as quickly as possible.
}

无论 OpenGL 绘制的 3D 画面多么复杂和优美,实质上它们都是由许许多多的点、线、
多边形
等基本几何对象构成的,而这也是 OpenGL 可以提供的最基本的绘制功能。如果你
有足够的时间和耐心,可以使用 OpenGL 的这些基本对象去构造绚丽多彩的 3D 画面。因
此,学习 OpenGL 的简单 3D 建模方法是步入 OpenGL 程序设计领域的第一步,也是不可
或缺的一步。
说明:
像是颜色,大小(点,线)这类属性都在glBegin()之前规定,在glBegin()内规定无效,而在glBegin()内规定的是绘制操作

(因为我试过一部分qwq,可以试试看,感觉是这样)

OpenGL采用的是状态机的方式,用户设定一种状态,程序照此运行。如:
(1)glBegin(GL_LINES)设定画线状态。main()函数中的几个glut前缀函数是OpenGL提供的工具库,我们关注的是display()函数,它是我们真正绘图的地方。
(2)与颜色有关的函数:

1)函数glColor3f()以RGB方式设置颜色,
    格式为:glColor3f(red, green, blue),每种颜色值在(0.0, 1.0)之间。
    为了能显示更多的颜色,最好把系统设置成16位真彩色模式。
    函数glVertex2i(x, y)设置整型二维顶点。
 (2) glColor4ub 函数
 函数原型: void WINAPI glColor4ub(
   GLubyte red,
   GLubyte green,
   GLubyte blue,
   GLubyte alpha
);
参数:
  红
  当前颜色的新红色值。

  绿
  当前颜色的新绿色值。

  蓝
  当前颜色的新蓝色值。

  alpha
  当前颜色的新 alpha 值。
  (3)glClearColor(1.0, 1.0, 1.0, 0.0);  
  Set display-window color to white.
  把新开的窗口背景设置为白色

(3)OpenGL 虽然分别提供了二维和三维顶点的绘制方法,但二维图形不过是三维图形的
特殊情况(z 分量为 0),在三维顶点绘制指令中,如果用户设定二维坐标(x, y),OpenGL 就
会自动令 z=0。因此,这里将三维基本图元和二维基本图元放在一起介绍。
OpenGL 提供的描述点、线、多边形的绘制机制必须通过 glBegin()和 glEnd()函数配对
来完成,下面对这两个函数作简要说明。
void glBegin(GLenum mode)
功能:描述一个几何图元顶点序列的开始。
参数说明
mode 指出图元的类型。类型可以是下面中的任一个值。

GL_POINTS		画点
GL_LINES		画线,每两个顶点(Vertex)为一组
GL_LINE_STRIP	画线,把若干个顶点顺次连成折线
GL_LINE_LOOP	画线,把若干个顶点顺次连成封闭折线
GL_TRIANGLES	画三角形,每三个顶点为一组
GL_QUADS		画四边形,每四个顶点为一组
GL_POLYGON		画多边形
还有GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_QUADS_STRIP 等等。
//下面这两个看不懂不要紧,可以不看,下方有图,有助于理解
GL_TRIANGLE_STRIP strip:带状,条状的意思
              在绘制朝一个方向延展的图形时选择它。  
                
                 绘制一组相互连接的三角形。
                 为前两个顶点之后的每个顶点定义一个三角形。
                 对于奇数n,顶点n、n + 1和n + 2定义三角形n。
                 对于偶数n,顶点n + 1、n和n + 2定义三角形n。
                 绘制n - 2个三角形。
GL_TRIANGLE_FAN   fan:扇形
                  在绘制扇形、圆形时选择它。
GL_QUAD_STRIP     绘制一组连通的四边形。在第一对顶点之后,
                  每对顶点定义一个四边形。
                  顶点2n - 1,2n, 2n + 22n + 1定义了四边形n。
                  绘制了n /2 - 1个四边形。
                  注意,从条形数据构造四边形所使用的顶点顺序
                  与独立数据所使用的顺序不同。

在这里插入图片描述

在这里插入图片描述

void glEnd (void)
功能:标记顶点表的结束。
在 OpenGL 中,所有的图元绘制都是在这对函数中完成的。

参考文章:
1.OpenGL 理解GL_TRIANGLE_STRIP、GL_TRIANGLE_FAN等绘制三角形序列的三种方式
2.【OpenGL】十五、OpenGL 绘制三角形 ( 绘制 GL_TRIANGLE_FAN 三角形扇 )
3.OpenGL 解析glBegin()
看到图三,那我们是不是可以试着用它来画圆呢?
接下来我们说一说基本图元:

用到的函数有
   glVertex//画点
   glPointSize//规定点的大小
  1. 点的绘制
    OpenGL中的点定义为一个方块,默认状态下,一般的绘制点就是绘制显示屏幕的一个像素。在OpenGL中一个点是当作一个n维(n=2,3,4)向量来处理的。如果调用函数用glVertex2f(2.0, 1.0)指定一个顶点的坐标(2.0, 1.0),则在实际计算中OpenGL是处理点(2.0, 1.0, 0.0),即OpenGL中用二维向量表示的点自动地将这个点的z值赋以0.0。
glVertex{2,3,4}{sifd}(V)(TYPE coords);
参数说明:
coords:用一个数组或用齐次坐标(x, y, z, w)赋顶点坐标
例如:
glVertex2f(1.5,2.6); 
glVertex2i(1,2); 
glVertex3d(2.12,3.48,6.57); 
glVertex3f(50.0,50.0,0.0); 
glVertex4f(1.3,2.0,-4.2,1.0); 
glVertex3sv(const Glshort *v);

程序执行到 glBegin()和 glEnd()时,就开始绘图操作。请看下面的例子:

glBegin(GL_POINTS); 
glVertex3f(0.0,0.0,0.0) 
glVertex3f(50.0,50.0,50.0) 
glEND(); 

glBegin()的参数 GL_POINTS 告诉 OpenGL,下面的顶点应被解释并绘制为点,它们将
转换为两个具体的点,并被绘制出来,其颜色为默认值指明的颜色。
2) 点的大小
OpenGL 提供了可以控制点的大小的函数。点大小的默认值是一个像素。可以用函数

修改这个值,以设定点的大小:
void glPointsize(GLfloat size) //具体代码看博客glPointsize()
首先解释一下:走样,什么是走样?汉语字典给的定义是:变样,失去原有的样子。
反走样,也就是不让它走样;
是否启动反走样,对绘制点操作有一定影响。如果没有启动反走样,所绘制的点是一
个正方形块,浮点数四舍五入为整数宽度;如果启动反走样,则画一个圆形像素集,边界
像素用低的颜色强度绘制,用浮点数不进行四舍五入,从而使所画的点看上去很光滑。

线

相关的博文:OpenGL基础(二):线

用到的函数有:
    glVertex//画点
    glLineStipple//启动点画线模式,stipple v.点画,点刻,点彩n.点画,点刻法
    glEnable(GL_LINE_STIPPLE)//开启点画线
    glDisable(GL_LINE_STIPPLE)//关闭点画线用 
    glLineWidth//同点的大小道理一样

(1) 用线型属性可以绘制虚线或点线,在 OpenGL 中统称为点画线。为了使用点画线,必
须用以下指令先启动点画线模式。
void glLineStipple (GLint factor,GLushort pattern);
此命令有以下参数
factor 是一个 1~255 的值,它表示 pattern 参数中所规定的像素的重复次数,即 pattern
参数中每一位能影响的像素数。
pattern 是画线操作时的一个样板。它是二进制的一个 0 和 1 的序列,在这个序列中 0
表示不画点,1 表示画点。
如果启动点画线操作,线上的点由 pattern 决定是否绘制,即从 pattern 的最低位开始,
逐个绘制线段上的点,如果式样用完后,线段还没有画完,则需重新装入样板。以下例子
说明此函数的应用

glLineStipple (10x3F07) 

此命令执行时,0x3F07 转化为二进制为 0011 1111 0000 0111。在画线操作时,首先绘
制开始的 3 个像素点,接下来 5 个点不绘制,6 个点绘制,2 个点不绘制。如果点画线的样
板用完,则将从头开始。
上例中,若 factor=2,那么 pattern 实际上就成为:00001111 11111111 00000000
00111111,结果为,6 个像素点画,10 个像素点不画,12 个像素点画,4 个像素点不画。
启动点画线用 glEnable(GL_LINE_STIPPLE)
关闭点画线用 glDisable(GL_LINE_STIPPLE)
(2)线宽:

glLineWidth(GLfloat width);

示例
图形
可以先试试看如何做到图中所示
在这里插入图片描述

代码如下:

#include <GL/glut.h>
void init()
{
	glClearColor(1.0, 1.0, 1.0, 0.0);
	glMatrixMode(GL_PROJECTION);       // Set projection parameters.
	gluOrtho2D(0.0, 200.0, 0.0, 150.0);
}

void f()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLineWidth(10);//线宽
	glEnable(GL_LINE_STIPPLE);
	glLineStipple(3, 0xAAAA);//开启点画线
	glColor3f(1.0, 0.0, 1.0);//设置颜色

	glBegin(GL_LINES);
	glVertex2i(20, 20);
    glVertex2i(50, 50);
	glEnd();
	
	glDisable(GL_LINE_STIPPLE);
	glColor3f(0.0, 0.0, 1.0);
	glBegin(GL_LINES);
	glVertex2i(70, 30);
	glVertex2i(100, 50);
	glEnd();
	glFlush();
}

int main(int argc,char *argv[])
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
	glutInitWindowSize(400, 400);
	glutInitWindowPosition(100, 100);
	glutCreateWindow("3.25");
	init();
	glutDisplayFunc(f);
	glutMainLoop();
	return 0;
}

多边形

相关博客:
OpenGL基础(三):三角形
OpenGL基础(四):四边形

用到的函数:
    glPolygonStipple()//图案填充
    glEnable(GL_POLYGON_STIPPLE)//启动多边形点画式样。
    glDisable(GL_POLYGON_STIPPLE)//关闭多边形点画式样。

glPolygonStipple 点画多边形
在这里插入图片描述

示例:

画线
用 GL_LINES

#include <GL/glut.h>      // (or others, depending on the system in use)
void init(void)
{
	glClearColor(1.0, 1.0, 1.0, 0.0);  // Set display-window color to white.
	glMatrixMode(GL_PROJECTION);       // Set projection parameters.
	gluOrtho2D(0.0, 200.0, 0.0, 150.0);//gluOrtho2D 函数定义二维正交投影矩阵。
}
void lineSegment(void)
{
	glClear(GL_COLOR_BUFFER_BIT);  // Clear display window.
	glColor3f(0.0, 0.0, 1.0);      // Set line segment color to red.
	glBegin(GL_LINES);
	glVertex2i(180, 15);       // Specify line-segment geometry.
	glVertex2i(10, 145);

	glEnd();
	glFlush();     // Process all OpenGL routines as quickly as possible.
}
void main(int argc, char** argv)
{
	glutInit(&argc, argv);                         // Initialize GLUT.
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);   // Set display mode.
	glutInitWindowPosition(50, 100);   // Set top-left display-window position.
	glutInitWindowSize(400, 400);      // Set display-window width and height.
	glutCreateWindow("An Example OpenGL Program"); // Create display window.
	init();                            // Execute initialization procedure.
	glutDisplayFunc(lineSegment);       // Send graphics to display window.
	glutMainLoop();                    // Display everything and wait.
}

在这里插入图片描述

画圆
头文件
用GL_POLYGON

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

                                   3.16 

同理,半圆可以这样画
在这里插入图片描述

在这里插入图片描述

窗口改变

借鉴的是博主xie_zi的文章
窗口改变时,图形也会改变
在这里插入图片描述

为了窗口改变时,保证初始化窗口不是正方形的时候渲染也不会变形出错。
在这里插入图片描述

void glutReshapeFunc(void(*func)int width,int height));
glutReshapeFunc(g(w,h));//main函数中调用
void g(int w,int h)
{// 防止除数即高度为0
 // (你可以设置窗口宽度为0).
       if(h == 0)
           h = 1;
     float ratio = 1.0* w /h;
     // 单位化投影矩阵。
       glMatrixMode(GL_PROJECTION);
       glLoadIdentity();
   // 设置视口大小为增个窗口大小
       glViewport(0, 0, w, h);
   // 设置正确的投影矩阵
      gluPerspective(45,ratio,1,1000);
    //下面是设置模型视图矩阵
     glMatrixMode(GL_MODELVIEW);
     glLoadIdentity();
     gluLookAt(0.0,0.0,5.0, 0.0,0.0,-1.0,0.0f , 1.0f , 0.0f  );
}

没学习线代,我也看着挺懵逼,(等我学会了再来补充吧)

                              2023.3.17 星期五

动画

博主的文章
main()函数:
增加些额外的设置。首先告诉GLUT我们想要一个双缓冲区。双缓冲区通过在后一个缓冲区里绘画,并不停交换前后缓冲区(可见缓冲区),来产生平滑的动画。使用双缓冲区可以预防闪烁。

glutInitDisplayMode(GL_DEPTH|GLUT_DOUBLE|GLUT_RGBA);

接着我们要做的是告诉GLUT,当应用程序空闲的时候渲染函数应该被调用。这导致GLUT一直调用渲染函数而产生动画。GLUT提供了一个函数:glutIdleFunc.这个函数使另一个函数在程序空闲的时候就会被调用。

void glutIdleFunc(void(*func)(void));

参数:

func:在程序空闲的时候就会被调用的函数的函数名。

按照我们的想法,当程序空闲时应该调用的函数是我们先前定义的渲染函数: renderScene。由于OpenGL默认没有开启深度测试,我们还要开启它,这样我们才能知道哪个物体在前面,哪个物体在后面。深度测试的开启在main()函数里,下面看看现在的main函数。

void main(int argc, char **argv) {
   
         glutInit(&argc, argv); 
         // 在这里设置双缓冲区。 
         glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
         glutInitWindowPosition(100,100);
       glutInitWindowSize(320,320);
       glutCreateWindow("3D Tech- GLUT Tutorial");
       glutDisplayFunc(renderScene);//画图
           // 这里让程序空闲时调用renderScene,
      glutIdleFunc(renderScene);//动画
         glutReshapeFunc(changeSize);//防止窗口改变
         //开启深度测试。
       glEnable(GL_DEPTH_TEST);
        glutMainLoop();   
}
  

float angle=0.0;
void renderScene(void) {
      //注意我们这里清除了深度缓冲区。 
         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//1
         //保存当前模型视图矩阵。  
         glPushMatrix(); //2
         glRotatef(angle,0.0,1.0,0.0);//3
         glBegin(GL_TRIANGLES);
     glVertex3f(-0.5,-0.5,0.0); 
       glVertex3f (0.5,0.0,0.0);
     glVertex3f (0.0,0.5,0.0); 
         glEnd();
         // 弹出堆栈
       glPopMatrix();//4
         // 交换缓冲区
       glutSwapBuffers();//5 
         // 让angle自动增加。
          angle++;  //6
          //新增了6句话
}

对 5 的解释

用法

void glutSwapBuffers(void);
描述

对用于当前窗口的图层执行缓冲区交换。
具体来说, glutSwapBuffers 将当前窗口 
使用的层的后台缓冲区的内容提升为 前端缓冲区的内容。
然后,后台缓冲区的内容 变得未定义。
更新通常在垂直期间进行 监视器的回溯,
而不是在调用 glutSwapBuffers 后立即回溯。

隐式 glFlush 由 glutSwapBuffers 在返回之前完成。 
后续的 OpenGL 命令可以在调用 glutSwapBuffer 后立即发出,
但在缓冲区交换之前不会执行 已完成。

如果使用的层不是双缓冲的,则 glutSwapBuffers 不起作用。
//有点懵逼是吧,是的,我也是qwq,别骂我,我就是为了记个笔记,为了以后理解了再来补充的qwq
                      2023.3.18 星期六

键盘控制

学习时参考
博主的文章qwq
可以通过键盘让图形变色,是的,它很炫酷
在这里给出了完整代码

#include <GL/glut.h>
#include <iostream>
#include <math.h>
const int n = 100;
const GLfloat R = 0.3f;
const GLfloat r = 0.6f;
const GLfloat Pi = 3.1415926;
float red = 1.0, blue = 1.0, green = 1.0;

float angle = 0.0;
void processSpecialKeys(int key, int x, int y) {
		switch (key) {
		case GLUT_KEY_F1:
			red = 1.0;
			green = 0.0;
			blue = 0.0; break;//红色
		case GLUT_KEY_F2:
			red = 0.0;
			green = 1.0;
			blue = 0.0; break;//绿色
		case GLUT_KEY_F3:
			red = 0.0;
			green = 0.0;
			blue = 1.0; break;//深蓝色
		case GLUT_KEY_F4:
			red = 1.0;
			green = 0.6;
			blue = 0.9; break;//粉色
		case GLUT_KEY_F5:
			red = 0.0;
			green = 0.6;
			blue = 0.9; break;//蓝色
		case GLUT_KEY_F6:
			red = 0.0;
			green = 1.0;
			blue = 0.9; break;//浅绿色
		case GLUT_KEY_F7:
			red = 0.0;
			green = 0.8;
			blue = 0.9; break;//浅绿色
		}
}




void f(void) {
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glPushMatrix();
	glRotatef(angle, 0.0, 1.0, 0.0);

	// glColor3f设置绘制三角形的颜色。
	glColor3f(red, green, blue);

	glBegin(GL_POLYGON);
	for (int i = 0; i < n; i++)
	{
		glVertex2f(R*cos(2 * Pi / n * i), R*sin(2 * Pi / n * i));
	}
	glEnd();
	glPopMatrix();
	angle++;
	glutSwapBuffers();
}

void changesize(int w, int h)
{
	{// 防止除数即高度为0
	 // (你可以设置窗口宽度为0).
		if (h == 0)
			h = 1;
		float ratio = 1.0* w / h;
		// 单位化投影矩阵。
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		// 设置视口大小为增个窗口大小
		glViewport(0, 0, w, h);
		// 设置正确的投影矩阵
		gluPerspective(45, ratio, 1, 1000);
		//下面是设置模型视图矩阵
		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
		gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, -1.0, 0.0f, 1.0f, 0.0f);
	}
}

void main(int argc, char** argv) {
	glutInit(&argc, argv);

	// 在这里设置双缓冲区。
	glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(320, 320);
	glutCreateWindow("3D Tech- GLUT Tutorial");
	glutDisplayFunc(f);

	glutSpecialFunc(processSpecialKeys);

	// 这里让程序空闲时调用renderScene,
	glutIdleFunc(f);
	/*glutReshapeFunc(changeSize);*/

	//开启深度测试。
	glEnable(GL_DEPTH_TEST);
	glutMainLoop();
}
                                   2023.3.19 星期日

场景漫游

文章场景漫游
这篇文章绘制了雪人,让我们以照相的视角进行移动
代码如下,可以贴来试试

#include <math.h>
#include <GL/glut.h>

#include <stdlib.h>

static float angle = 0.0, ratio;
static float x = 0.0f, y = 1.75f, z = 5.0f;
static float lx = 0.0f, ly = 0.0f, lz = -1.0f;
static GLint snowman_display_list;

void changeSize(int w, int h)
{

	// 防止被0除.
		if (h == 0)
			h = 1;

	ratio = 1.0f * w / h;
	// Reset the coordinate system before modifying修改前请重置坐标系统
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	//设置视口为整个窗口大小
		glViewport(0, 0, w, h);

	//设置可视空间
		gluPerspective(45, ratio, 1, 1000);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(x, y, z,
		x + lx, y + ly, z + lz,
		0.0f, 1.0f, 0.0f);
}
//下面我们定义显示列表,绘制雪人,初始化场景,渲染场景。
void drawSnowMan() {

	glColor3f(1.0f, 1.0f, 1.0f);

	//画身体
		glTranslatef(0.0f, 0.75f, 0.0f);
	glutSolidSphere(0.75f, 20, 20);


	// 画头
		glTranslatef(0.0f, 1.0f, 0.0f);
	glutSolidSphere(0.25f, 20, 20);

	// 画眼睛
		glPushMatrix();
	glColor3f(0.0f, 0.0f, 0.0f);
	glTranslatef(0.05f, 0.10f, 0.18f);
	glutSolidSphere(0.05f, 10, 10);
	glTranslatef(-0.1f, 0.0f, 0.0f);
	glutSolidSphere(0.05f, 10, 10);
	glPopMatrix();

	// 画鼻子
		glColor3f(1.0f, 0.5f, 0.5f);
	glRotatef(0.0f, 1.0f, 0.0f, 0.0f);
	glutSolidCone(0.08f, 0.5f, 10, 2);
}

GLuint createDL() {
	GLuint snowManDL;

	//生成一个显示列表号
		snowManDL = glGenLists(1);

	// 开始显示列表
		glNewList(snowManDL, GL_COMPILE);

	// call the function that contains 
	// the rendering commands
	drawSnowMan();

	// endList
	glEndList();

	return(snowManDL);
}

void initScene() {

	glEnable(GL_DEPTH_TEST);
	snowman_display_list = createDL();
}


void renderScene(void) {
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	//画了一个地面

		glColor3f(0.9f, 0.9f, 0.9f);
	glBegin(GL_QUADS);
	glVertex3f(-100.0f, 0.0f, -100.0f);
	glVertex3f(-100.0f, 0.0f, 100.0f);
	glVertex3f(100.0f, 0.0f, 100.0f);
	glVertex3f(100.0f, 0.0f, -100.0f);
	glEnd();

	//画了36个雪人

		for (int i = -3; i < 3; i++)
			for (int j = -3; j < 3; j++) {
				glPushMatrix();
				glTranslatef(i*10.0, 0, j * 10.0);
				glCallList(snowman_display_list);;
				glPopMatrix();
			}
	glutSwapBuffers();
}

void orientMe(float ang) {

	lx = sin(ang);
	lz = -cos(ang);
	glLoadIdentity();
	gluLookAt(x, y, z,
		x + lx, y + ly, z + lz,
		0.0f, 1.0f, 0.0f);
}
void moveMeFlat(int direction) {
	x = x + direction * (lx)*0.1;
	z = z + direction * (lz)*0.1;
	glLoadIdentity();
	gluLookAt(x, y, z,
		x + lx, y + ly, z + lz,
		0.0f, 1.0f, 0.0f);
}

//这里我们建立函数,处理特殊键按下消息。使用左右方向键旋转照相机,也就是改变视线。上下方向键使照相机沿视线前后移动。
void inputKey(int key, int x, int y) {

	switch (key) {
	case GLUT_KEY_LEFT:
		angle -= 0.01f;
		orientMe(angle); break;
	case GLUT_KEY_RIGHT:
		angle += 0.01f;
		orientMe(angle); break;
	case GLUT_KEY_UP:
		moveMeFlat(1); break;
	case GLUT_KEY_DOWN:
		moveMeFlat(-1); break;
	}
}
	int main(int argc, char **argv)
	{
		glutInit(&argc, argv);
		glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
		glutInitWindowPosition(100, 100);
		glutInitWindowSize(640, 360);
		glutCreateWindow("SnowMen from 3D-Tech");

		initScene();

		glutSpecialFunc(inputKey);

		glutDisplayFunc(renderScene);
		glutIdleFunc(renderScene);

		glutReshapeFunc(changeSize);

		glutMainLoop();

		return(0);
	}

先告一段落,因为还没学习线代,矩阵部分有点吃力,以后会继续补充

  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值