实 验 报 告
一、实验目的
- 掌握三维图形的显示原理和方法,掌握三维观察的原理和方法;
- 掌握OpenGL中矩阵堆栈函数的使用,会使用堆栈函数进行复杂场景的组装。
- 掌握OpenGL中三维观察变换常用的函数的使用方法,了解三维模型的贴图方法;
- 掌握自由曲线的生成方法,熟练掌握B样条曲线的生成原理、方法和特点。
二、实验内容与实验步骤
太阳系:
使用线框球体绘制函数实现球体绘制。当按下键盘“D”或“d”时,行星将实现自转;按下键盘“Y”或“y”时,行星将绕太阳公转。实现以下两个内容:
(1)给行星加上卫星;
(2)实现自动旋转功能,即卫星绕行星自动旋转、行星自动自传同时绕太阳公转。
(3)(选做)程序例子2是一个粘贴了纹理图像的自转的地球的例子(位图文件见实验任务附件ear.bmp),理解其中的纹理图像装载和使用方法,自制贴图图片,仿照这个程序编写九大行星运行的3D动画。
B样条曲线绘制:
在OpenGL 中实现动态输入任意多个控制点(控制点个数大于等于4),采用三次参数样条曲线,按照分段拼接的方式生成逼近任意多个控制点组成的多边形的光滑曲线。并按照给定的控制点个数绘制B样条曲线。
其基函数递归公式为:
取,
将上式带入B样条定义式得:
其中一段3次参数B样条曲线由四个控制点P0、P1、P2和P3生成,调和矩阵为中间的4*4矩阵,在编写程序时尽量考虑减少无用的运算,尽量提高运算的效率。
要求生成曲线的过程按照下面的交互方式输入:
(1)在控制点输入状态下,点击左键,增加一个控制点,并绘制上一个控制点到当前控制点的连线。
(2)点击左键增加一个控制点,点击右键按照已选择的控制点生成B样条曲线。
(3)设置一种控制键的处理可以清除屏幕上的图形,重新进行控制点输入状态。
三、实验环境
- 操作系统:macOS Big Sur Version 11.6
- 调试软件:Xcode Version 13.0
- 上机地点:信息楼Bxxx
- 机器台号:xx
四、实验过程与分析
地球公转&自转:
首先单实现地球绕太阳的公转和自转。使用线框球体绘制函数实现球体绘制。当按下键盘“D”或“d”时,行星将实现自转;按下键盘“Y”或“y”时,行星将绕太阳公转。
太阳系:
坐标变换过程:
太阳:不变,在中心即可。
地球:用循环改变SolarAngle的值,调用glRotatef()函数实现公转;
用循环改变OwnAxisAngle的值,调用glRotatef()实现自转;
调用glTranslatef()函数将其平移至公转轨道,并随时间在轨道上改变位置。
月球:类似地球的坐标变换过程。
函数作用:
以上函数的功能分别是:加载贴图;控制台显示提示;绘制太阳;初始化;绘制图形;调整图形;键盘与鼠标的事件;主函数。
具体实现见代码中的注释:
load_texture()函数:
int load_texture(const char* file_name, int width, int height, int depth, GLenum colour_type, GLenum filter_type)
{
GLubyte* raw_bitmap;
FILE* file;
//if ((file = fopen_s(file_name, "rb")) == NULL)
if ((file = fopen(file_name, "rb")) == NULL)
{
return 1;
}
raw_bitmap = (GLubyte*)malloc(width * height * depth * (sizeof(GLubyte)));
if (raw_bitmap == NULL)
{
fclose(file);
return 2;
}
fread(raw_bitmap, width * height * depth, 1, file);
fclose(file);
// 设置过滤类型
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter_type);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter_type);
// 设置纹理环境
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, width, height, colour_type,
GL_UNSIGNED_BYTE, raw_bitmap);
free(raw_bitmap);
glDisable(GL_TEXTURE_2D);
return 0;
}
Load_texture()函数:
void LoadTextures(GLuint texture_id, int MaxNrOfTextures)
{
// 第一种纹理
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); //控制所读取数据的对齐方式
glGenTextures(MaxNrOfTextures, &texture_id); // 生成纹理的数量-MaxNrOfTextures 存储纹理索引-texture_id
glBindTexture(GL_TEXTURE_2D, 1); //将一个命名的纹理绑定到一个纹理目标上
if (load_texture("/Users/kqp12_27/Desktop/Xcode-OpenGL/Mouse copy 12/Mouse/ear.bmp", 512, 128, 3, GL_BGR_EXT, GL_NEAREST)) //读取此bmp文件
{
exit(1);
}
// 第二种纹理
glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
glGenTextures(MaxNrOfTextures, &texture_id);
glBindTexture(GL_TEXTURE_2D, 2);
if (load_texture("/Users/kqp12_27/Desktop/一些课📖/计图实验/实验三/太阳系/moon copy.bmp",88,63, 3, GL_BGR_EXT, GL_NEAREST))
{
exit(1);
}
// 第三种纹理
glPixelStorei(GL_UNPACK_ALIGNMENT, 3);
glGenTextures(MaxNrOfTextures, &texture_id);
glBindTexture(GL_TEXTURE_2D, 3);
if (load_texture("/Users/kqp12_27/Desktop/一些课📖/计图实验/实验三/太阳系/sun.bmp",500, 400, 3, GL_BGR_EXT, GL_NEAREST))
{
exit(1);
}
}
init()函数:
void init(void)
{
//地球
Planet1.size = 0.4f;
Planet1.sections = 16.0f;
Planet1.posX = 0.0f;
Planet1.posY = 0.0f;
Planet1.posZ = 1.4f;
Planet1.OwnAxisAngle = 0.0f;
Planet1.SolarAngle = 60.0f;
Planet1.TextureID = 1;
//月球
Planet2.size = 0.2f;
Planet2.sections = 16.0f;
Planet2.posX = 0.0f;
Planet2.posY = 0.0f;
Planet2.posZ = 1.4f;
Planet2.OwnAxisAngle = 0.0f;
Planet2.SolarAngle = 60.0f;
Planet2.TextureID = 2;
glClearColor(0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_FLAT);
LoadTextures(texture_id1, 1);
glEnable(GL_TEXTURE_2D);
glClearDepth(1.0f); // 设置深度缓存
glDepthFunc(GL_LEQUAL); // 选择深度测试方式
glEnable(GL_DEPTH_TEST); // 开启深度测试
glShadeModel(GL_SMOOTH); // 阴暗处理采用平滑方式
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // 最精细的透视计算
return;
}
display()函数:
void display(void)
{
// 地球公转
Planet1.SolarAngle += 1.0f * ROTATION_SPEED;
if (Planet1.SolarAngle >= 360) { Planet1.SolarAngle -= 360; }
// 地球自转
Planet1.OwnAxisAngle += 0.5f;
if (Planet1.OwnAxisAngle >= 360) { Planet1.OwnAxisAngle -= 360; }
// 月球公转
Planet2.SolarAngle += 7.0f * ROTATION_SPEED;
if (Planet2.SolarAngle >= 360) { Planet2.SolarAngle -= 360; }
// 月球自转
Planet2.OwnAxisAngle += 1.0f;
if (Planet2.OwnAxisAngle >= 360) { Planet2.OwnAxisAngle -= 360; }
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 清除颜色和深度缓存
glColor3f(1.0, 0.0, 0.0);
glColor3f(1.0, 1.0, 1.0);
glColor3f(0.7f, 0.7f, 0.7f);
glBegin(GL_LINE_LOOP);
// 绘制轨道
for (int l = 0; l < 360; l++)
{
glVertex3f((float)cos(l * ((float)3.14159 / (float)180)) * Planet1.posZ, 0.0f, (float)sin(l * ((float)3.14159 / (float)180)) * Planet1.posZ);
}
glEnd();
glPushMatrix();
// 地球
// 坐标变换,使地球在公转轨道上转
glRotatef(Planet1.SolarAngle, 0, -1, 0); //旋转
glTranslatef(Planet1.posX, Planet1.posY, Planet1.posZ); //平移
glRotatef(Planet1.OwnAxisAngle, 0, -1, 0);
glBindTexture(GL_TEXTURE_2D, 1); //设置纹理
GLUquadricObj* q = gluNewQuadric();
gluQuadricDrawStyle(q, GLU_FILL);
gluQuadricNormals(q, GLU_SMOOTH);
gluQuadricTexture(q, GL_TRUE);
gluSphere(q, Planet1.size, 50, 40); //画球
gluDeleteQuadric(q);
glBindTexture(GL_TEXTURE_2D, 0);
// 月球
glRotatef(Planet2.SolarAngle, 0, 1, 0);
glTranslatef(0.5*Planet2.posX, 0.5*Planet2.posY, 0.5*Planet2.posZ);
glRotatef(Planet2.OwnAxisAngle, 0, -1, 0);
glRotatef(90.0, 1.0, 0.0, 0.0);
glBindTexture(GL_TEXTURE_2D, 2);
GLUquadricObj* q2 = gluNewQuadric();
gluQuadricDrawStyle(q2, GLU_FILL);
gluQuadricNormals(q2, GLU_SMOOTH);
gluQuadricTexture(q2, GL_TRUE);
gluSphere(q2, Planet2.size, 50, 40);
gluDeleteQuadric(q2);
glPopMatrix();
glLoadIdentity();
draw_sun(); //绘制太阳
gluLookAt(R * cos(b / 180 * 3.1415926) * sin(a / 180 * 3.1415926), R * sin(b / 180 * 3.1415926), R * cos(b / 180 * 3.1415926) * cos(a / 180 * 3.1415926), 0.0, 0.0, 0.0, cos((90 - b) / 180 * 3.1415926) * sin((a + 180) / 180 * 3.1415926), sin((90 - b) / 180 * 3.1415926), cos((90 - b) / 180 * 3.1415926) * cos((a + 180) / 180 * 3.1415926)); //观察角度
glutSwapBuffers();
}
调试:
问题一:开始时两个星球都绕着太阳转。
解决办法:在第一次变换后不立刻进行出栈操作,而是在第一次变换的基础上再添加一次变换,这样可以让月球绕地球转。
问题二:初始化时两个星球的纹理一样,没法分别设置纹理。
解决办法:通过对glBindTexture函数的添加操作,添加了纹理对象,解决了问题。
B样条曲线绘制:
流程图:
主要思想:
动态输入任意多个控制点(控制点个数大于等于4),采用三次参数样条曲线,按照分段拼接的方式生成逼近任意多个控制点组成的多边形的光滑曲线。并按照给定的控制点个数绘制B样条曲线。
调试:
问题一:点击鼠标右键时偶尔会卡住。
解决办法:鼠标事件里出现了问题,修改后可以正常运行了。
代码:
void Bspline(Point a, Point b, Point c, Point d) {
glPointSize(2);
glColor3d(0, 0, 0);
glBegin(GL_LINE_STRIP);
for (int i = 0; i <= 1000; i++)
{
double t = 0.001 * i;
double r[4];
r[0] = -t * t * t + 3 * t * t - 3 * t + 1;
r[1] = 3 * t * t * t - 6 * t * t + 4;
r[2] = -3 * t * t * t + 3 * t * t + 3 * t + 1;
r[3] = t * t * t;
double x = 0, y = 0;
x += r[0] * a.x + r[1] * b.x + r[2] * c.x + r[3] * d.x;
y += r[0] * a.y +r[1] * b.y + r[2] * c.y + r[3] * d.y;
x /= 6.0;
y /= 6.0;
glVertex2d(x,y);
}
glEnd();
}
void Display()
{
glClear(GL_COLOR_BUFFER_BIT);
//画点
glPointSize(7);
glColor3d(0, 0, 1);
glBegin(GL_POINTS);
for (int i = 0; i < p.size(); i++)
glVertex2d(p[i].x, p[i].y);
glEnd();
//画线
glLineWidth(2);
glColor3d(1, 0, 1);
glBegin(GL_LINE_STRIP);
for (int i = 0; i < p.size(); i++)
glVertex2d(p[i].x, p[i].y);
glEnd();
if (sta == 1 && p.size() >= 3)
for (int i = 0; i < p.size() - 3; i++)
Bspline(p[i], p[i + 1], p[i + 2], p[i + 3]);
glFlush();
}
void Mouse(int button, int state, int x, int y)
{
if (sta == 0 && button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
Point t;
t.x = x; t.y = y;
p.push_back(t);
glutPostRedisplay();
}
if (sta == 0 && button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) {
sta = 1;
glutPostRedisplay();
}
}
void Keyboard(unsigned char key, int x, int y)
{
if (key == 'd')
{
glClearColor(1, 1, 1, 0);
glClear(GL_COLOR_BUFFER_BIT);
p.clear();
sta = 0;
glutPostRedisplay();
}
}
五、 实验结果总结
地球公转&自转:(视频见附件地球.mov)
太阳系:(视频见附件太阳系.mov)
太阳系(选):(视频见附件太阳系(选).mov)【这其实是我从git上偷了一个 555】
B样条曲线:
2个控制点重合:
效果:曲线在该点附近与两点间形成的直线基本重合,在该点则有一定的距离和弧度。
(只有一个位置是2个控制点重合)
应用:
- 用于绘制基本重合于连接相邻两点线段,但在拐点处的曲率于控制点的位置有关的线段;
- 用于在局部绘制出类似“圆角”的形状。
3个控制点重合:
效果:曲线在该点附近与两点间形成的直线基本重合,曲线也与该点重合。
(只有一个位置是3个控制点重合)
应用:
- 绘制与直接连接的线段相同的线段;
- 在局部绘制类似“尖角”的形状。
(所有位置都是3个控制点重合)
六、 附录
- 其他解决方案/设想:无。
-
参考资料:
- 教材、PPT。
- B-Spline样条曲线及其性质_BRAND-NEO的博客-CSDN博客_准均匀b样条曲线
- OpenGL学习笔记 之三 (简单示例 太阳月亮地球)_weixin_38167262的博客-CSDN博客
- 用上周的作业:画一个太阳、地球、月亮的运动模型来剖析OpenGL中变换乃至整个绘制的秘密_Luo Xiao C的博客-CSDN博客
- 回答思考题
Q:在OpenGL中提供给了哪几类函数能修改矩阵工作栈的数据?
A:Opengl中常用两个变换堆栈,一个是glMatrixMode(GL_MODELVIEW),它一开始时候栈顶是一个单位矩阵,一般堆栈大小是32个矩阵。一个是glMatrixMode(GL_PROJECTION),正交或者透视投影,一开始时候没有栈顶单位矩阵所以需要glLoadIdentity()单位矩阵到栈顶,投影堆栈大小一般是2个,要2个目的是一个程序中既可以实现透视投影,也可以切换到正交投影(例如绘制文本)。 如果glPushMatrix()太多大于堆栈容量那么会报错,如果glPopMatrix()小于等于一个那么也会报错 。glMatrixMode(GL_TEXTURE)是纹理堆栈,也有相应的变换矩阵。
Q:OpenGL中提供了哪几种二次曲面模型?怎样调用使用?
A:圆面、扇形、圆柱、圆锥、球等。创建二次曲面声明类型的指针GLUquadricObj*。利用上述指针,利用二次曲面模型的类,如gluCylinde(GLUquadric* quad, GLdouble base, GLdouble top,GLdouble height,GLint slices,,GLint stacks)圆柱,设置相应的参数来创建该二次曲面的对象,设置二次曲面的绘制风格,设置法线风格,设置二次曲面的绘制方向,设置纹理,调用二次曲面的绘制函数。
Q:B样条曲线对比Bezier曲线的算法有哪些好处?
A:B样条方法是在保留Bezier方法的优点,同时克服其由于整体表示带来不具有局部性质的缺点,及解决在描述复杂形状时带来的连接问题下提出来的,当控制点个数多时控制多边形对曲线的控制不会减弱;可以对曲线进行局部修改。
完整代码:
项目一:(太阳系)
#define GL_SILENCE_DEPRECATION
//include\gl
#include <stdlib.h>
#include <iostream>
#include <GLUT/glut.h>
#include <math.h>
#define ROTATION_SPEED 0.1
static int year = 0, day = 0;
GLuint texture_id1;
int start = 0;
int ori_x;
int ori_y;
struct Planet
{
float size, sections, posX, posY, posZ, SolarAngle, OwnAxisAngle;
int TextureID;
};
struct Planet Planet1;
struct Planet Planet2;
struct Planet Planet3;
float R = 8;
float a = 0;
float b = 0;
int load_texture(const char* file_name, int width, int height, int depth, GLenum colour_type, GLenum filter_type)
{
GLubyte* raw_bitmap;
FILE* file;
//if ((file = fopen_s(file_name, "rb")) == NULL)
if ((file = fopen(file_name, "rb")) == NULL)
{
return 1;
}
raw_bitmap = (GLubyte*)malloc(width * height * depth * (sizeof(GLubyte)));
if (raw_bitmap == NULL)
{
fclose(file);
return 2;
}
fread(raw_bitmap, width * height * depth, 1, file);
fclose(file);
// 设置过滤类型
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter_type);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter_type);
// 设置纹理环境
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, width, height, colour_type,
GL_UNSIGNED_BYTE, raw_bitmap);
free(raw_bitmap);
glDisable(GL_TEXTURE_2D);
return 0;
}
void LoadTextures(GLuint texture_id, int MaxNrOfTextures)
{
// 第一种纹理
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); //控制所读取数据的对齐方式
glGenTextures(MaxNrOfTextures, &texture_id); // 生成纹理的数量-MaxNrOfTextures 存储纹理索引-texture_id
glBindTexture(GL_TEXTURE_2D, 1); //将一个命名的纹理绑定到一个纹理目标上
if (load_texture("/Users/kqp12_27/Desktop/Xcode-OpenGL/Mouse copy 12/Mouse/ear.bmp", 512, 128, 3, GL_BGR_EXT, GL_NEAREST)) //读取此bmp文件
{
exit(1);
}
// 第二种纹理
glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
glGenTextures(MaxNrOfTextures, &texture_id);
glBindTexture(GL_TEXTURE_2D, 2);
if (load_texture("/Users/kqp12_27/Desktop/一些课📖/计图实验/实验三/太阳系/moon copy.bmp",88,63, 3, GL_BGR_EXT, GL_NEAREST))
{
exit(1);
}
// 第三种纹理
glPixelStorei(GL_UNPACK_ALIGNMENT, 3);
glGenTextures(MaxNrOfTextures, &texture_id);
glBindTexture(GL_TEXTURE_2D, 3);
if (load_texture("/Users/kqp12_27/Desktop/一些课📖/计图实验/实验三/太阳系/sun.bmp",500, 400, 3, GL_BGR_EXT, GL_NEAREST))
{
exit(1);
}
}
void draw_sun(){
glBindTexture(GL_TEXTURE_2D, 3);
GLUquadricObj* q3 = gluNewQuadric();
gluQuadricDrawStyle(q3, GLU_FILL);
gluQuadricNormals(q3, GLU_SMOOTH);
gluQuadricTexture(q3, GL_TRUE);
gluSphere(q3, 0.1002, 50,40);
gluDeleteQuadric(q3);
}
void init(void)
{
//地球
Planet1.size = 0.4f;
Planet1.sections = 16.0f;
Planet1.posX = 0.0f;
Planet1.posY = 0.0f;
Planet1.posZ = 1.4f;
Planet1.OwnAxisAngle = 0.0f;
Planet1.SolarAngle = 60.0f;
Planet1.TextureID = 1;
//月球
Planet2.size = 0.2f;
Planet2.sections = 16.0f;
Planet2.posX = 0.0f;
Planet2.posY = 0.0f;
Planet2.posZ = 1.4f;
Planet2.OwnAxisAngle = 0.0f;
Planet2.SolarAngle = 60.0f;
Planet2.TextureID = 2;
glClearColor(0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_FLAT);
LoadTextures(texture_id1, 1);
glEnable(GL_TEXTURE_2D);
glClearDepth(1.0f); // 设置深度缓存
glDepthFunc(GL_LEQUAL); // 选择深度测试方式
glEnable(GL_DEPTH_TEST); // 开启深度测试
glShadeModel(GL_SMOOTH); // 阴暗处理采用平滑方式
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // 最精细的透视计算
return;
}
void display(void)
{
// 地球公转
Planet1.SolarAngle += 1.0f * ROTATION_SPEED;
if (Planet1.SolarAngle >= 360) { Planet1.SolarAngle -= 360; }
// 地球自转
Planet1.OwnAxisAngle += 0.5f;
if (Planet1.OwnAxisAngle >= 360) { Planet1.OwnAxisAngle -= 360; }
// 月球公转
Planet2.SolarAngle += 7.0f * ROTATION_SPEED;
if (Planet2.SolarAngle >= 360) { Planet2.SolarAngle -= 360; }
// 月球自转
Planet2.OwnAxisAngle += 1.0f;
if (Planet2.OwnAxisAngle >= 360) { Planet2.OwnAxisAngle -= 360; }
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 清除颜色和深度缓存
glColor3f(1.0, 0.0, 0.0);
glColor3f(1.0, 1.0, 1.0);
glColor3f(0.7f, 0.7f, 0.7f);
glBegin(GL_LINE_LOOP);
// 绘制轨道
for (int l = 0; l < 360; l++)
{
glVertex3f((float)cos(l * ((float)3.14159 / (float)180)) * Planet1.posZ, 0.0f, (float)sin(l * ((float)3.14159 / (float)180)) * Planet1.posZ);
}
glEnd();
glPushMatrix();
// 地球
// 坐标变换,使地球在公转轨道上转
glRotatef(Planet1.SolarAngle, 0, -1, 0); //旋转
glTranslatef(Planet1.posX, Planet1.posY, Planet1.posZ); //平移
glRotatef(Planet1.OwnAxisAngle, 0, -1, 0);
glBindTexture(GL_TEXTURE_2D, 1); //设置纹理
GLUquadricObj* q = gluNewQuadric();
gluQuadricDrawStyle(q, GLU_FILL);
gluQuadricNormals(q, GLU_SMOOTH);
gluQuadricTexture(q, GL_TRUE);
gluSphere(q, Planet1.size, 50, 40); //画球
gluDeleteQuadric(q);
glBindTexture(GL_TEXTURE_2D, 0);
// 月球
glRotatef(Planet2.SolarAngle, 0, 1, 0);
glTranslatef(0.5*Planet2.posX, 0.5*Planet2.posY, 0.5*Planet2.posZ);
glRotatef(Planet2.OwnAxisAngle, 0, -1, 0);
glRotatef(90.0, 1.0, 0.0, 0.0);
glBindTexture(GL_TEXTURE_2D, 2);
GLUquadricObj* q2 = gluNewQuadric();
gluQuadricDrawStyle(q2, GLU_FILL);
gluQuadricNormals(q2, GLU_SMOOTH);
gluQuadricTexture(q2, GL_TRUE);
gluSphere(q2, Planet2.size, 50, 40);
gluDeleteQuadric(q2);
glPopMatrix();
glLoadIdentity();
draw_sun(); //绘制太阳
gluLookAt(R * cos(b / 180 * 3.1415926) * sin(a / 180 * 3.1415926), R * sin(b / 180 * 3.1415926), R * cos(b / 180 * 3.1415926) * cos(a / 180 * 3.1415926), 0.0, 0.0, 0.0, cos((90 - b) / 180 * 3.1415926) * sin((a + 180) / 180 * 3.1415926), sin((90 - b) / 180 * 3.1415926), cos((90 - b) / 180 * 3.1415926) * cos((a + 180) / 180 * 3.1415926)); //观察角度
glutSwapBuffers();
}
void reshape(int w, int h)
{
glViewport(0, 0, (GLsizei)w, (GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, (GLfloat)w / (GLfloat)h, 0.1, 20.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void keyboard(unsigned char key, int x, int y)
{
switch (key) {
case 'w':
R -= 0.1;
break;
case 's':
R += 0.1;
break;
case 27:
exit(0);
break;
default:
break;
}
}
void processMouse(int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
start = 1;
ori_x = x;
ori_y = y;
}
if (button == GLUT_LEFT_BUTTON && state == GLUT_UP)
{
start = 0;
}
}
void onMouseMove(int x, int y)
{
if (start == 1)
{
a -= (x - ori_x) / 2;
b += (y - ori_y) / 2;
ori_x = x;
ori_y = y;
}
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(1000, 600);
glutInitWindowPosition(100, 100);
glutCreateWindow(argv[0]);
init();
glutDisplayFunc(display);
glutIdleFunc(display);
draw_sun();
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutMouseFunc(processMouse);
glutMotionFunc(onMouseMove);
glutMainLoop();
return 0;
}
项目一(选)(git上偷的太阳系):
#define GL_SILENCE_DEPRECATION
#include<stdio.h>
#include<stdlib.h>
#include <GLUT/glut.h>
#include<math.h>
#include<time.h>
#define PI 3.14
float angleMoon=0.0, angleEarth=0.0,angleAstroid=0.0,
angleMars=0.0,
angleMercury=0.0,
angleVenus=0.0,
angleJupiter=0.0,
angleSaturn=0.0,
angleUranus=30.0,
angleNeptune=60.0;
GLfloat sx=0.2,sy=0.2,sz=0.2;
int planet1;
GLfloat black[]={0.0f,0.0f,0.0f,1.0f};
GLfloat white[]={1.0f,1.0f,1.0f,1.0f};
GLfloat blue[]={0.0f,0.0f,0.9f,1.0f};
GLfloat er[]={0.0f,5.0f,0.9f,1.0f};
GLfloat yellow[]={0.7f,0.2f,0.0f,1.0f};
GLfloat qAmb[]={0.1,0.1,0.1,1.0};
GLfloat qDif[]={1.0,1.0,1.0,1.0};
GLfloat qSpec[]={.50,.50,.50,.10};
GLfloat qPos[]={0,0,0,0.1};
GLfloat sc[8]={0.295 , 0.40,0.50, 0.60,0.80,1.0,1.05,1.13};
double ang=2*PI/300;
double angular=2*PI/50;
void initLighting()
{
//glMaterialfv(GL_FRONT,GL_AMBIENT,yellow);
//glMaterialfv(GL_FRONT,GL_SPECULAR,yellow);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT7);
glLightfv(GL_LIGHT7,GL_AMBIENT,qAmb);
glLightfv(GL_LIGHT7,GL_DIFFUSE,qDif);
glLightfv(GL_LIGHT7,GL_SPECULAR,qSpec);
//glMaterialfv(GL_FRONT,GL_DIFFUSE,yellow);
}
void myinit()
{
glClearColor(0.0,0.0,0.0,0.0); //backgroundcolor is green
//gluOrtho2D(0,699,0,699);
glPointSize(1.0);
glLineWidth(2.0);
}
void background()
{
glBegin(GL_QUADS);
glColor3f(0.0,0.00,0.00);
glVertex3f(-01.00,01.00,1);
glColor3f(.20,0.0,0.70);
glVertex3f(01.00,1.00,1);
glColor3f(0,0.0,0.0);
glVertex3f(1.00,-1.00,1);
glColor3f(.70,.10,.20);
glVertex3f(-1.00,-1.00,1);
glEnd();
}
void orbit()
{
glColor3f(0.5,0.5,0.5);
int i=0;
for(i=0;i<8;i++){
glPushMatrix();
if(i==5)
{glRotatef(45,1.0,0.0,0.0);}
else
{glRotatef(63,1.0,0.0,0.0);}
glScalef(sc[i],sc[i],sc[i]);
glBegin(GL_POINTS);
double ang1=0.0;
int i=0;
for(i=0;i<300;i++)
{glVertex2d(cos(ang1),sin(ang1));
ang1+=ang; }
glEnd();
glPopMatrix();
}
}
void draw(void)
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
background();
orbit();
glLoadIdentity();
glPushMatrix();
glEnable(GL_DEPTH_TEST);
glEnable(GL_COLOR_MATERIAL);
glPushMatrix();
glColor3f(0.7,0.5,0.0);
glScalef(sx,sy,sz);
glLightfv(GL_LIGHT7,GL_POSITION,qPos);
glMaterialfv(GL_FRONT_AND_BACK,GL_EMISSION,yellow);
glutSolidSphere(1,50,50);
glMaterialfv(GL_FRONT_AND_BACK,GL_EMISSION,black);
glPopMatrix();
glScalef(0.2,0.2,0.2);
glPushMatrix();
glRotatef(angleMercury,0.0,1.0,-0.5);
glTranslatef(1.5,0.0,0.0);
glColor3f(1.0,0.9,0.0);
glScalef(0.08,0.08,0.08);
glutSolidSphere(1,50,50);
glPopMatrix();
glPushMatrix();
glRotatef(angleVenus,0.0,1.0,-0.5);
glTranslatef(2.0,0.0,0.0);
glColor3f(0.9,0.1,0.0);
glScalef(0.1,0.1,0.1);
glutSolidSphere(1,50,50);
glPopMatrix();
glPushMatrix();
glRotatef(angleEarth,0.0,1.0,-0.5);
glTranslatef(2.5,0.0,0.0);
glColor3f(0.0,0.1,0.7);
glScalef(0.23,0.23,0.23);
glutSolidSphere(1,50,50);
glPushMatrix();
glRotatef(angleMoon,0.0,0.1,0.05);
glTranslatef(1.3,0.0,0.0);
glColor3f(1.0,1.0,1.0);
glScalef(0.5,0.5,0.5);
glutSolidSphere(0.5,50,50);
glPopMatrix();//moon made
glPopMatrix();//earth made
glPushMatrix();
glRotatef(angleMars,0.0,1.0,-0.5);
glTranslatef(-3.0,0.0,0.0);
glColor3f(0.05,0.05,0.01);
glScalef(0.17,0.17,0.17);
glutSolidSphere(1,50,50);
glPopMatrix();
glPushMatrix();
glColor3f(3.30,3.30,3.30);
glRotatef(63,1.0,0.0,0.0);
int j=0,i=0,div=90;float siz=2;
float scl[4]={3.3,3.4,3.35,3.2};
for(j=0;j<4;j++)
{glPushMatrix();siz-=0.3;
glPointSize(siz);
glScalef(scl[j],scl[j],scl[j]);
glBegin(GL_POINTS);
double ang1=0.0 -angleAstroid,a=(2*PI)/div;
for(i=0;i<div;i++)
{glVertex2d(cos(ang1),sin(ang1));
ang1+=a; }
div+=10;
glEnd();
glPopMatrix();
}
glPopMatrix();//astroid made
glPushMatrix();
glRotatef(angleJupiter,0.0,1.0,-0.5);
glTranslatef(-4.0,0.0,0.0);
glColor3f(0.4,0.2,0.0);
glScalef(0.5,0.5,0.5);
glutSolidSphere(1,50,50);
glPushMatrix();
glRotatef(angleMoon,1.0,-0.5,0.0);
glTranslatef(0.0,0,1.1);
glColor3f(1.0,1.0,1.0);
glScalef(0.1,0.1,0.1);
glutSolidSphere(0.5,50,50);
glPopMatrix();//moon made
glPopMatrix();
glPushMatrix();
glRotatef(angleSaturn,0.0,1.0,-1.0);
glTranslatef(-5.0,0.0,0.0);
glColor3f(0.9,0.0,0.0);
glScalef(0.4,0.4,0.4);
glutSolidSphere(1,50,50);
glPushMatrix();
glRotatef(45,1.0,0.0,0.0);
glPointSize(3);
glColor3f(5.0,3.0,1.0);
glScalef(1.2,1.2,1.2);
glBegin(GL_POINTS);
double ang1=0.0;
i=0;
for(i=0;i<50;i++)
{glVertex2d(cos(ang1),sin(ang1));
ang1+=angular; }
glEnd();
glPointSize(2);
glPopMatrix();//ring made
glPopMatrix();
glPushMatrix();
glRotatef(angleUranus,0.0,1.0,-0.5);
glTranslatef(5.2,0.0,0.0);
glColor3f(0.0,0.5,0.9);
glScalef(0.23,0.23,0.23);
glutSolidSphere(1,50,50);
glPopMatrix();
glPushMatrix();
glRotatef(angleNeptune,0.0,1.0,-0.5);
glTranslatef(-5.7,0.0,0.0);
glColor3f(0.0,0.0,0.9);
glScalef(0.2,0.2,0.2);
glutSolidSphere(1,50,50);
glPopMatrix();
glPopMatrix();
glFlush();
}
void update(int value){
if((angleMoon>=0 && angleMoon<180) )
{sx-=0.0003;sy-=0.0003;sz-=0.0003;}
else{sx+=0.0003;sy+=0.0003;sz+=0.0003;}
angleMoon+=2;
if(angleMoon>360){
angleMoon-=360;}
angleEarth+=0.7;
if(angleEarth>360){
angleEarth-=360;}
angleMercury+=2;
if(angleMercury>360){
angleMercury-=360;}
angleVenus+=0.9;
if(angleVenus>360){
angleVenus-=360;}
angleMars+=0.5;
if(angleMars>360){
angleMars-=360;}
angleJupiter+=0.2;
if(angleJupiter>360){
angleJupiter-=360;}
angleSaturn+=0.1;
if(angleSaturn>360){
angleSaturn-=360;}
angleUranus+=0.05;
if(angleUranus>360){
angleUranus-=360;}
angleNeptune+=0.02;
if(angleNeptune>360){
angleNeptune-=360;}
angleAstroid+=0.002;
if(angleAstroid>360){
angleAstroid-=360;}
glutPostRedisplay();
glutTimerFunc(20,update,0);
}
int main(int argc, char **argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
glutInitWindowPosition(0,0);
glutInitWindowSize(700,700);
glutCreateWindow("Solar System");
initLighting();
myinit();
glutDisplayFunc(draw);
glutTimerFunc(25,update,0);
glutMainLoop();
return 0;
}
项目二(B样条):
#define GL_SILENCE_DEPRECATION
#include<vector>
#include<GLUT/glut.h>
using namespace std;
int sta = 0;//状态显示
struct Point
{
int x;
int y;
};
vector<Point> p;
void Bspline(Point a, Point b, Point c, Point d) {
glPointSize(2);
glColor3d(0, 0, 0);
glBegin(GL_LINE_STRIP);
for (int i = 0; i <= 1000; i++)
{
double t = 0.001 * i;
double r[4];
r[0] = -t * t * t + 3 * t * t - 3 * t + 1;
r[1] = 3 * t * t * t - 6 * t * t + 4;
r[2] = -3 * t * t * t + 3 * t * t + 3 * t + 1;
r[3] = t * t * t;
double x = 0, y = 0;
x += r[0] * a.x + r[1] * b.x + r[2] * c.x + r[3] * d.x;
y += r[0] * a.y +r[1] * b.y + r[2] * c.y + r[3] * d.y;
x /= 6.0;
y /= 6.0;
glVertex2d(x,y);
}
glEnd();
}
void Display()
{
glClear(GL_COLOR_BUFFER_BIT);
//画点
glPointSize(7);
glColor3d(0, 0, 1);
glBegin(GL_POINTS);
for (int i = 0; i < p.size(); i++)
glVertex2d(p[i].x, p[i].y);
glEnd();
//画线
glLineWidth(2);
glColor3d(1, 0, 1);
glBegin(GL_LINE_STRIP);
for (int i = 0; i < p.size(); i++)
glVertex2d(p[i].x, p[i].y);
glEnd();
if (sta == 1 && p.size() >= 3)
for (int i = 0; i < p.size() - 3; i++)
Bspline(p[i], p[i + 1], p[i + 2], p[i + 3]);
glFlush();
}
void Mouse(int button, int state, int x, int y)
{
if (sta == 0 && button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
Point t;
t.x = x; t.y = y;
p.push_back(t);
glutPostRedisplay();
}
if (sta == 0 && button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) {
sta = 1;
glutPostRedisplay();
}
}
void Keyboard(unsigned char key, int x, int y)
{
if (key == 'd')
{
glClearColor(1, 1, 1, 0);
glClear(GL_COLOR_BUFFER_BIT);
p.clear();
sta = 0;
glutPostRedisplay();
}
}
void Reshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, w, h, 0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowPosition(100, 100);
glutInitWindowSize(600, 600);
glutCreateWindow("B样条曲线");
glClearColor(1, 1, 1, 0);
glutDisplayFunc(Display);
glutReshapeFunc(Reshape);
glutMouseFunc(Mouse);
glutKeyboardFunc(Keyboard);
glutMainLoop();
return 0;
}
文章来源:https://www.toymoban.com/news/detail-498632.html
有用的话点点赞捏!!文章来源地址https://www.toymoban.com/news/detail-498632.html
到了这里,关于【计算机图形学】【实验报告】太阳系绘制、B样条曲线绘制(附代码)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!