DEV C++ 计算机图形学期末作业中等难度示例(1)

目录

一、系统需求与技术架构

三维基础图形绘制系统分析

1. ​功能模块划分​

2. ​核心技术实现​

3. ​数据结构设计​

4. ​交互与性能优化​

5. ​光照与材质系统​

6. ​视角与投影控制​

7. ​技术难点与解决方案​

8. ​扩展性设计​

二、核心代码解析

2.1 几何体建模实现

2.1.1 立方体构建算法

2.1.2 球体参数化生成

2.1.3 圆柱体分层构建

三、图形变换系统

3.1 变换层级控制

3.2 视角切换机制

四、光照与材质系统

4.1 Phong光照模型实现

4.2 材质属性配置

五、交互控制系统

5.1 键盘事件处理

六、扩展方向与优化建议

6.1 功能扩展

6.2 性能优化

七、完整代码


1. 三维基础图形绘制

功能:基于 OpenGL 或 Three.js,绘制立方体、球体、圆柱体等三维几何体。

要求:实现几何体的旋转、平移、缩放,添加光照效果,展示不同视角下的几何体。

    一、系统需求与技术架构

    三维基础图形绘制系统分析

    1. ​功能模块划分
    • 几何体管理
      支持立方体、球体、圆柱体等基本几何体的参数化生成,需定义顶点生成算法(如球体的经纬度细分、圆柱体的截面环形顶点分布)。
    • 变换操作模块
      实现模型矩阵的旋转、平移、缩放操作,需处理局部坐标系与世界坐标系的转换逻辑。
    • 光照系统
      支持环境光、漫反射、镜面反射(Phong模型),需计算法线向量、光源衰减(点光源)及视角方向。
    • 视角控制
      提供轨道控制器或第一人称视角,支持相机位置、朝向的实时调整,需处理视锥体裁剪与投影矩阵更新。
    2. ​核心技术实现
    • 坐标变换流水线
      • 模型矩阵​:通过四元数或欧拉角实现物体的旋转,避免万向节锁;平移与缩放基于世界坐标系原点或局部中心。
      • 视图矩阵​:相机位置与朝向的逆矩阵,支持透视投影(近大远小)与正交投影(等比例)。
      • 投影矩阵​:根据视场角(FOV)和宽高比动态更新,适配窗口尺寸变化。
    • 光照计算
      • 法线变换​:将顶点法线从模型空间转换到世界空间,需与模型矩阵的逆转置矩阵相乘。
      • 光源交互​:平行光方向全局一致,点光源需计算衰减因子(如 1/(a + b*d + c*d²))。
      • 着色器分工​:顶点着色器传递切线与副切线,片段着色器计算高光强度与法线贴图采样。
    3. ​数据结构设计
    • 几何体数据池
      存储几何体的顶点、法线、纹理坐标、索引数据,支持动态加载(如从OBJ文件解析)。
      示例结构:
      struct Mesh {
          std::vector<glm::vec3> vertices;  // 顶点坐标
          std::vector<glm::vec3> normals;   // 法线向量
          std::vector<unsigned int> indices;// 绘制索引
          Material material;                // 材质属性
      };
    • 变换状态管理
      记录每个物体的当前变换矩阵、动画插值进度(如旋转角度增量)及层级关系(父子节点的矩阵叠加)。
    4. ​交互与性能优化
    • 用户输入处理
      • 键盘事件:绑定快捷键(如WASD移动相机,Q/E旋转视角)。
      • 鼠标事件:拖拽实现物体旋转(基于偏移量计算欧拉角),滚轮缩放视图。
    • 渲染优化
      • 实例化渲染​:对相同几何体复用绘制调用,减少Draw Call。
      • 遮挡剔除​:通过视锥体或层次包围盒(BVH)跳过不可见物体。
      • LOD技术​:根据相机距离切换几何体细节层级(如远距离用低模替代)。
    5. ​光照与材质系统
    • 光源类型支持
      • 平行光​:方向固定,阴影投射需正交投影矩阵。
      • 点光源​:位置可变,需计算六个面的阴影贴图(立方体贴图)。
    • 材质参数化
      定义漫反射颜色、高光指数、粗糙度等属性,支持PBR(基于物理的渲染)工作流。
    6. ​视角与投影控制
    • 相机模式切换
      • 轨道模式​:围绕目标物体旋转,保持固定距离与仰角。
      • 自由模式​:通过WASD移动相机位置,鼠标调整视角方向。
    • 投影切换
      动态调整近/远裁剪平面,适配场景规模(如室内场景用大FOV,室外用小FOV)。
    7. ​技术难点与解决方案
    • 模型矩阵累积误差
      频繁的旋转操作可能导致万向节锁,改用四元数插值(SLERP)平滑过渡。
    • 硬表面反走样
      启用多重采样抗锯齿(MSAA)或后处理FXAA,解决几何体边缘锯齿问题。
    • 动态光源性能
      点光源过多时,使用延迟渲染(G-Buffer)分离光照计算阶段,减少全屏着色开销。
    8. ​扩展性设计
    • 插件化几何体生成器
      通过接口扩展支持自定义几何体(如导入STL文件或程序化生成地形)。
    • 多后端支持
      抽象渲染上下文,兼容OpenGL ES(移动端)与WebGL(浏览器端)。
    • 物理引擎集成
      预留碰撞检测接口,支持刚体动力学与刚柔体交互。

    二、核心代码解析

    2.1 几何体建模实现

    2.1.1 立方体构建算法
    void drawCube(float size) {
        float s = size / 2.0f;
        glBegin(GL_QUADS);
          // +X 面法线(1,0,0)
          glVertex3f(s, -s, -s); // 顶点顺序遵循右手法则
          glVertex3f(s,  s, -s);
          glVertex3f(s,  s,  s);
          glVertex3f(s, -s,  s);
          // ...其他面类似定义
        glEnd();
    }

    技术要点​:

    • 顶点顺序严格遵循右手法则确定法线方向
    • 每个面独立定义,便于单独控制材质属性
    2.1.2 球体参数化生成
    void drawSphere(float radius, int slices, int stacks) {
        for(int i = 0; i < stacks; ++i) {
            float lat0 = M_PI * (-0.5f + i/stacks); 
            float z0 = radius * sinf(lat0);
            // 极坐标转笛卡尔坐标
            float x = cosf(lng) * zr; 
            float y = sinf(lng) * zr;
            glNormal3f(x, y, z); // 法线与顶点位置相同(球体特性)
        }
    }

    数学原理​:

    • 纬度带划分:纬度角lat = -π/2 + i/stacks * π
    • 经度环划分:经度角lng = 2π * j/slices
    2.1.3 圆柱体分层构建
    void drawCylinder(float radius, float height, int slices) {
        // 侧面:使用QUAD_STRIP连接上下底圆
        for(int i = 0; i <= slices; ++i) {
            float theta = 2*M_PI*i/slices;
            float x = cosf(theta)*radius;
            // 顶点沿Z轴双向延伸
            glVertex3f(x, y,  halfH); 
            glVertex3f(x, y, -halfH);
        }
        // 顶/底面:TRIANGLE_FAN闭合曲面
    }

    拓扑结构​:

    • 侧面使用四边形带连接上下底圆周
    • 顶/底面使用三角形扇闭合

    三、图形变换系统

    3.1 变换层级控制

    glPushMatrix();
      glTranslatef(0, 0, transZ); // 第三级变换
      glRotatef(angX, 1, 0, 0);   // 第二级变换
      glRotatef(angY, 0, 1, 0);   // 第一级变换
      glScalef(scaleAll, scaleAll, scaleAll); // 基础缩放
      // 绘制物体(第四级变换)
    glPopMatrix();

    变换顺序​:
    缩放 → 旋转 → 平移(固定管线矩阵操作顺序)

    3.2 视角切换机制

    void display() {
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        if (viewMode == 0) {
            gluLookAt(0, 5, 10, 0,0,0, 0,1,0); // 正交视角
        } else if (viewMode == 1) {
            gluLookAt(0,10,0, 0,0,0, 0,0,1);  // 顶视图
        } else {
            gluLookAt(10,0,0, 0,0,0, 0,1,0);  // 侧视图
        }
    }

    观察矩阵​:

    • 通过改变eye位置实现视角切换
    • up向量始终指向Y轴方向

    四、光照与材质系统

    4.1 Phong光照模型实现

    // 光照参数设置
    GLfloat ambient[]  = {0.2f, 0.2f, 0.2f, 1.0f}; // 环境光
    GLfloat diffuse[]  = {0.8f, 0.8f, 0.8f, 1.0f}; // 漫反射
    GLfloat specular[] = {1.0f, 1.0f, 1.0f, 1.0f}; // 镜面反射
    glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);

    光照计算​:
    总光照强度 = I_a×k_a + I_d×(N·L)×k_d + I_s×(R·V)^n×k_s

    4.2 材质属性配置

    glMaterialfv(GL_FRONT, GL_SPECULAR, specular); // 镜面反射系数
    glMaterialf (GL_FRONT, GL_SHININESS, 50.0f); // 高光锐度

    材质影响​:

    • 高光区域大小由shininess值控制
    • 不同几何体设置差异材质增强辨识度

    五、交互控制系统

    5.1 键盘事件处理

    void keyboard(unsigned char key, int, int) {
        switch (key) {
          case 'w': angX += 5; break; // X轴旋转
          case 'a': angY += 5; break; // Y轴旋转
          case 'z': scaleAll += 0.1f; break; // 均匀缩放
          case 'v': viewMode = (viewMode+1)%3; break; // 视角切换
        }
        glutPostRedisplay();
    }

    控制逻辑​:

    • 旋转角度增量控制(每次±5度)
    • 缩放因子线性增减(步长0.1)

    六、扩展方向与优化建议

    6.1 功能扩展

    扩展功能实现方案技术难点
    纹理映射SOIL库加载位图UV坐标参数化
    动态LOD基于视距调整细分级别几何体简化算法
    阴影投射阴影映射(Shadow Mapping)深度纹理采样

    6.2 性能优化

    1. 显示列表缓存几何体数据
    2. 启用顶点数组减少API调用
    3. 使用VBO/IBO优化渲染管线

    七、完整代码

    #define GLUT_DISABLE_ATEXIT_HACK
    #include <windows.h>    // Win32 窗口
    #include <GL/gl.h>
    #include <GL/glu.h>
    #include <GL/glut.h>
    #include <cmath>
    
    // 窗口尺寸
    const int WIDTH  = 800;
    const int HEIGHT = 600;
    
    // 变换参数
    float angX     = 20.0f, angY     = 30.0f;   // 旋转角度
    float transZ   = -10.0f;                   // Z 方向平移
    float scaleAll = 1.0f;                     // 缩放因子
    
    int viewMode = 0;  // 0=透视,1=顶视,2=侧视
    
    // -------------------------------------------------------------------
    // 渲染立方体
    // -------------------------------------------------------------------
    void drawCube(float size) {
        float s = size / 2.0f;
        glBegin(GL_QUADS);
          // +X 面 (右)
          glNormal3f( 1,  0,  0);
          glVertex3f( s, -s, -s);
          glVertex3f( s,  s, -s);
          glVertex3f( s,  s,  s);
          glVertex3f( s, -s,  s);
          // -X 面 (左)
          glNormal3f(-1,  0,  0);
          glVertex3f(-s, -s,  s);
          glVertex3f(-s,  s,  s);
          glVertex3f(-s,  s, -s);
          glVertex3f(-s, -s, -s);
          // +Y 面 (上)
          glNormal3f( 0,  1,  0);
          glVertex3f(-s,  s, -s);
          glVertex3f(-s,  s,  s);
          glVertex3f( s,  s,  s);
          glVertex3f( s,  s, -s);
          // -Y 面 (下)
          glNormal3f( 0, -1,  0);
          glVertex3f(-s, -s,  s);
          glVertex3f(-s, -s, -s);
          glVertex3f( s, -s, -s);
          glVertex3f( s, -s,  s);
          // +Z 面 (前)
          glNormal3f( 0,  0,  1);
          glVertex3f(-s, -s,  s);
          glVertex3f( s, -s,  s);
          glVertex3f( s,  s,  s);
          glVertex3f(-s,  s,  s);
          // -Z 面 (后)
          glNormal3f( 0,  0, -1);
          glVertex3f( s, -s, -s);
          glVertex3f(-s, -s, -s);
          glVertex3f(-s,  s, -s);
          glVertex3f( s,  s, -s);
        glEnd();
    }
    
    // -------------------------------------------------------------------
    // 渲染球体
    // -------------------------------------------------------------------
    void drawSphere(float radius, int slices, int stacks) {
        for(int i = 0; i < stacks; ++i) {
            float lat0 = M_PI * (-0.5f + float(i)   / stacks);
            float z0   = radius * sinf(lat0);
            float zr0  = radius * cosf(lat0);
            float lat1 = M_PI * (-0.5f + float(i+1) / stacks);
            float z1   = radius * sinf(lat1);
            float zr1  = radius * cosf(lat1);
    
            glBegin(GL_QUAD_STRIP);
            for(int j = 0; j <= slices; ++j) {
                float lng = 2 * M_PI * float(j) / slices;
                float x = cosf(lng), y = sinf(lng);
                glNormal3f(x*zr0, y*zr0, z0);
                glVertex3f(x*zr0, y*zr0, z0);
                glNormal3f(x*zr1, y*zr1, z1);
                glVertex3f(x*zr1, y*zr1, z1);
            }
            glEnd();
        }
    }
    
    // -------------------------------------------------------------------
    // 渲染圆柱体
    // -------------------------------------------------------------------
    void drawCylinder(float radius, float height, int slices) {
        float halfH = height / 2.0f;
        // 侧面
        glBegin(GL_QUAD_STRIP);
        for(int i = 0; i <= slices; ++i) {
            float theta = 2 * M_PI * float(i) / slices;
            float x = cosf(theta), y = sinf(theta);
            glNormal3f(x, y, 0);
            glVertex3f(x*radius, y*radius,  halfH);
            glVertex3f(x*radius, y*radius, -halfH);
        }
        glEnd();
        // 顶部
        glBegin(GL_TRIANGLE_FAN);
          glNormal3f(0, 0, 1);
          glVertex3f(0, 0, halfH);
          for(int i = 0; i <= slices; ++i){
            float theta = 2 * M_PI * float(i) / slices;
            glVertex3f(cosf(theta)*radius, sinf(theta)*radius, halfH);
          }
        glEnd();
        // 底部
        glBegin(GL_TRIANGLE_FAN);
          glNormal3f(0, 0, -1);
          glVertex3f(0, 0, -halfH);
          for(int i = slices; i >= 0; --i){
            float theta = 2 * M_PI * float(i) / slices;
            glVertex3f(cosf(theta)*radius, sinf(theta)*radius, -halfH);
          }
        glEnd();
    }
    
    // -------------------------------------------------------------------
    // OpenGL 初始化
    // -------------------------------------------------------------------
    void initGL() {
        glEnable(GL_DEPTH_TEST);
        glEnable(GL_CULL_FACE);        // 通常开启面剔除
        glCullFace(GL_BACK);
        glEnable(GL_LIGHTING);
        glEnable(GL_LIGHT0);
        glEnable(GL_COLOR_MATERIAL);
    
        // 灯光属性
        GLfloat ambient[]  = {0.2f, 0.2f, 0.2f, 1.0f};
        GLfloat diffuse[]  = {0.8f, 0.8f, 0.8f, 1.0f};
        GLfloat specular[] = {1.0f, 1.0f, 1.0f, 1.0f};
        GLfloat position[] = {5.0f, 5.0f, 5.0f, 1.0f};
        glLightfv(GL_LIGHT0, GL_AMBIENT,  ambient);
        glLightfv(GL_LIGHT0, GL_DIFFUSE,  diffuse);
        glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
        glLightfv(GL_LIGHT0, GL_POSITION, position);
        glMaterialfv(GL_FRONT, GL_SPECULAR, specular);
        glMaterialf (GL_FRONT, GL_SHININESS, 50.0f);
    
        // 投影设置
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(45.0, double(WIDTH)/HEIGHT, 1.0, 100.0);
    }
    
    // -------------------------------------------------------------------
    // 渲染回调
    // -------------------------------------------------------------------
    void display() {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        if (viewMode == 0) {
            gluLookAt(0, 5, 10,   0, 0, 0,    0, 1, 0);        // 正常视角
        } else if (viewMode == 1) {
            gluLookAt(0, 10, 0,   0, 0, 0,    0, 0, 1);        // 顶视图(Z轴为上)
        } else {
            gluLookAt(10, 0, 0,   0, 0, 0,    0, 1, 0);        // 侧视图
        }
    
        glPushMatrix();
          glTranslatef(0, 0, transZ);
          glRotatef(angX, 1, 0, 0);
          glRotatef(angY, 0, 1, 0);
          glScalef(scaleAll, scaleAll, scaleAll);
    
          glColor3f(1, 0, 0);
          glPushMatrix();
            glTranslatef(-4, 0, 0);
            drawCube(2.0f);
          glPopMatrix();
    
          glColor3f(0, 1, 0);
          glPushMatrix();
            glTranslatef(0, 0, 0);
            drawSphere(1.5f, 24, 16);
          glPopMatrix();
    
          glColor3f(0, 0, 1);
          glPushMatrix();
            glTranslatef(4, 0, 0);
            drawCylinder(1.0f, 3.0f, 24);
          glPopMatrix();
        glPopMatrix();
    
        glutSwapBuffers();
    }
    
    // -------------------------------------------------------------------
    // 键盘交互
    // -------------------------------------------------------------------
    void keyboard(unsigned char key, int, int) {
        switch (key) {
          case 'w': angX     += 5;    break;
          case 's': angX     -= 5;    break;
          case 'a': angY     += 5;    break;
          case 'd': angY     -= 5;    break;
          case 'z': scaleAll += 0.1f; break;
          case 'x': scaleAll -= 0.1f; break;
          case 'i': transZ   += 1.0f; break;
          case 'k': transZ   -= 1.0f; break;
          case 'v': viewMode = (viewMode + 1) % 3; break;
          case 27:  exit(0);           break;
        }
        glutPostRedisplay();
    }
    
    // -------------------------------------------------------------------
    // 主函数
    // -------------------------------------------------------------------
    int main(int argc, char** argv) {
        glutInit(&argc, argv);
        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
        glutInitWindowSize(WIDTH, HEIGHT);
        glutCreateWindow("3D Primitives Demo (Fixed)");
    
        initGL();
        glutDisplayFunc(display);
        glutKeyboardFunc(keyboard);
        glutMainLoop();
        return 0;
    }
    

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值