【计算机图形学】【实验报告】太阳系绘制、B样条曲线绘制(附代码)

实 验 报 告

一、实验目的

  1. 掌握三维图形的显示原理和方法,掌握三维观察的原理和方法;
  2. 掌握OpenGL中矩阵堆栈函数的使用,会使用堆栈函数进行复杂场景的组装。
  3. 掌握OpenGL中三维观察变换常用的函数的使用方法,了解三维模型的贴图方法;
  4. 掌握自由曲线的生成方法,熟练掌握B样条曲线的生成原理、方法和特点。

二、实验内容与实验步骤

太阳系:

使用线框球体绘制函数实现球体绘制。当按下键盘“D”或“d”时,行星将实现自转;按下键盘“Y”或“y”时,行星将绕太阳公转。实现以下两个内容:

(1)给行星加上卫星;

(2)实现自动旋转功能,即卫星绕行星自动旋转、行星自动自传同时绕太阳公转。

(3)(选做)程序例子2是一个粘贴了纹理图像的自转的地球的例子(位图文件见实验任务附件ear.bmp),理解其中的纹理图像装载和使用方法,自制贴图图片,仿照这个程序编写九大行星运行的3D动画。

B样条曲线绘制:

在OpenGL 中实现动态输入任意多个控制点(控制点个数大于等于4),采用三次参数样条曲线,按照分段拼接的方式生成逼近任意多个控制点组成的多边形的光滑曲线。并按照给定的控制点个数绘制B样条曲线。

基函数递归公式为:

\begin{aligned} B_{k,1}(t)&=\left\{\begin{matrix} 1, & & {k\le t<k+1} \\ 0, & & {else} \end{matrix}\right. \\ B_{k,m}(t)&=\frac{t-k}{m-1}B_{k,m-1}(t)+\frac{k+1-t}{m-1}B_{k+1,m-1}(t) \end{aligned}

m=3

\begin{aligned} B_{0,4}(t)&=\frac{1}{6}(-t^3+3t^2-3t+1) \\ B_{1,4}(t)&=\frac{1}{6}(3t^3-6t^2+4)\\ B_{2,4}(t)&=\frac{1}{6}(-3t^3+3t^2+3t+1) \\ B_{3,4}(t)&=\frac{1}{6}t^3 \end{aligned}

将上式带入B样条定义式得:

\begin{aligned} p(t)&=\sum^n_{k=0}P_kB_{k,m} \\ &=[B_{0,4}(t) \ \ B_{1,4}(t) \ \ B_{2,4}(t) \ \ B_{3,4}(t)]\cdot\begin{bmatrix}P_0 \\ P_1 \\P_2 \\ P_3 \end{bmatrix} \\ &=\begin{bmatrix} t^3 & t^2 & t & 1 \end{bmatrix}\cdot\frac{1}{6}\cdot\begin{bmatrix} -1 & 3 & -3 & 1 \\ 3 & 6 & 3 & 0 \\ -3 & 0 & 3 & 0 \\ 1 & 4 & 1 & 0 \end{bmatrix}\cdot\begin{bmatrix}P_0 \\ P_1 \\P_2 \\ P_3 \end{bmatrix} \\ &= T\cdot M_B\cdot G_B \ \ \ \ \ t\in[0,1) \end{aligned}

其中一段3次参数B样条曲线由四个控制点P0、P1、P2和P3生成,调和矩阵为中间的4*4矩阵,在编写程序时尽量考虑减少无用的运算,尽量提高运算的效率。

要求生成曲线的过程按照下面的交互方式输入:

(1)在控制点输入状态下,点击左键,增加一个控制点,并绘制上一个控制点到当前控制点的连线。

(2)点击左键增加一个控制点,点击右键按照已选择的控制点生成B样条曲线。

(3)设置一种控制键的处理可以清除屏幕上的图形,重新进行控制点输入状态。

三、实验环境

  1. 操作系统:macOS Big Sur Version 11.6
  2. 调试软件:Xcode Version 13.0
  3. 上机地点:信息楼Bxxx
  4. 机器台号: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个控制点重合)

应用:

  1. 用于绘制基本重合于连接相邻两点线段,但在拐点处的曲率于控制点的位置有关的线段;
  2. 用于在局部绘制出类似“圆角”的形状。

3个控制点重合:

        效果:曲线在该点附近与两点间形成的直线基本重合,曲线也与该点重合。

(只有一个位置是3个控制点重合)

应用:

  1. 绘制与直接连接的线段相同的线段;
  2. 在局部绘制类似“尖角”的形状。

(所有位置都是3个控制点重合)

六、 附录

  1. 其他解决方案/设想:无。
  2. 参考资料:
    1. 教材、PPT
    2. B-Spline样条曲线及其性质_BRAND-NEO的博客-CSDN博客_准均匀b样条曲线
    3. OpenGL学习笔记 之三 (简单示例 太阳月亮地球)_weixin_38167262的博客-CSDN博客
    4. 用上周的作业:画一个太阳、地球、月亮的运动模型来剖析OpenGL中变换乃至整个绘制的秘密_Luo Xiao C的博客-CSDN博客
  3. 回答思考题

Q:在OpenGL中提供给了哪几类函数能修改矩阵工作栈的数据?

AOpengl中常用两个变换堆栈,一个是glMatrixMode(GL_MODELVIEW),它一开始时候栈顶是一个单位矩阵,一般堆栈大小是32个矩阵。一个是glMatrixMode(GL_PROJECTION),正交或者透视投影,一开始时候没有栈顶单位矩阵所以需要glLoadIdentity()单位矩阵到栈顶,投影堆栈大小一般是2个,要2个目的是一个程序中既可以实现透视投影,也可以切换到正交投影(例如绘制文本)。 如果glPushMatrix()太多大于堆栈容量那么会报错,如果glPopMatrix()小于等于一个那么也会报错 。glMatrixMode(GL_TEXTURE)是纹理堆栈,也有相应的变换矩阵。

QOpenGL中提供了哪几种二次曲面模型?怎样调用使用?

A圆面、扇形、圆柱、圆锥、球等。创建二次曲面声明类型的指针GLUquadricObj*。利用上述指针,利用二次曲面模型的类,如gluCylinde(GLUquadric* quad, GLdouble base, GLdouble top,GLdouble height,GLint slices,,GLint stacks)圆柱,设置相应的参数来创建该二次曲面的对象,设置二次曲面的绘制风格,设置法线风格,设置二次曲面的绘制方向,设置纹理,调用二次曲面的绘制函数。

QB样条曲线对比Bezier曲线的算法有哪些好处?

AB样条方法是在保留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;
}

​​​​​​​


有用的话点点赞捏!!

  • 7
    点赞
  • 60
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值