DEV C++ 计算机图形学期末作业简单示例(3)

3. 简单图形填充器

功能:实现纯色填充和渐变色填充功能,为绘制的封闭图形填充颜色。

要求:支持 RGB 颜色模式,可自定义渐变色起始与终止颜色,展示填充过程的动画效果。

目录

一、功能需求与技术路线

简单图形填充器分析

1. ​功能模块划分​

2. ​核心实现逻辑​

3. ​数据结构设计​

4. ​OpenGL实现策略​

5. ​交互与性能优化​

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

7. ​扩展性设计​

二、核心算法实现

2.1 颜色插值原理

2.1.1 线性插值公式

2.1.2 扫描线填充算法

三、代码架构解析

3.1 系统模块划分

3.2 关键代码实现

3.2.1 顶点渐变填充

3.2.2 扫描线动画实现

四、关键技术详解

4.1 双缓冲动画机制

4.2 颜色空间管理

五、功能扩展方向

5.1 填充模式增强

5.2 交互功能升级

六、完整代码


一、功能需求与技术路线

简单图形填充器分析

1. ​功能模块划分
  • 填充模式管理​:区分纯色填充与渐变色填充,支持动态切换模式。
  • 颜色输入模块​:支持RGB数值输入或颜色选择器交互,分别设置纯色、渐变起始/终止颜色。
  • 动画控制器​:管理填充进度(如从0%到100%逐步填充),控制动画时长与插值方式。
  • 图形数据扩展​:存储图形边界信息、填充状态(是否填充、动画进度)及渐变参数。
2. ​核心实现逻辑
  • 纯色填充算法​:
    • 扫描线填充​:针对凸多边形,按行扫描交点并填充区间。
    • 种子填充(边界/泛洪)​​:适用于任意封闭图形,需处理栈溢出风险。
    • OpenGL内置填充​:通过glPolygonMode(GL_FILL)直接绘制,但需确保图形闭合且无自交。
  • 渐变色填充算法​:
    • 线性渐变​:基于图形坐标系插值颜色(如从左到右),通过片段着色器计算片元颜色。
    • 径向渐变​:以图形中心为原点,按半径插值颜色,需计算片元到中心的距离。
    • 参数化渐变方向​:允许用户选择渐变轴(水平、垂直、对角线等)。
3. ​数据结构设计
  • 图形对象扩展​:
    • 存储图形类型、位置、尺寸等基础属性。
    • 新增填充属性:是否填充、纯色值(RGB)、渐变参数(起始/终止颜色、方向)、动画进度(0.0~1.0)。
  • 渐变方向枚举​:如HORIZONTALVERTICALDIAGONAL
4. ​OpenGL实现策略
  • 纯色填充​:
    • 使用glBegin(GL_POLYGON)绘制闭合路径,设置glColor3ub为纯色。
    • 启用深度测试避免重叠图形填充错误。
  • 渐变色填充​:
    • 顶点着色器​:传递渐变起止坐标或方向参数。
    • 片段着色器​:根据片元位置计算插值颜色(如线性渐变中根据片元坐标与渐变方向的投影比例插值颜色值)。
    • 动画实现​:通过glUniform1f传递动画进度参数,片段着色器根据进度动态裁剪填充区域(如仅填充进度≤当前进度的部分)。
5. ​交互与性能优化
  • 颜色输入交互​:
    • 提供RGB滑块或集成颜色选择器,实时更新预览效果。
  • 动画性能​:
    • 使用离屏渲染预计算渐变纹理,避免每帧重复计算。
    • 对静态图形缓存填充结果,减少GPU负载。
  • 抗锯齿处理​:启用混合(glBlendFunc)平滑填充边缘。
6. ​技术难点与解决方案
  • 复杂图形填充​:
    • 对非凸多边形使用扫描线算法或分割为三角形逐块填充。
  • 渐变方向对齐​:
    • 将渐变方向映射到世界坐标系,确保图形旋转时渐变方向一致。
  • 动画卡顿​:
    • 采用固定时间步长更新动画,避免帧率波动导致进度跳跃。
7. ​扩展性设计
  • 多渐变类型支持​:预留接口支持径向、圆锥渐变。
  • 填充模式混合​:允许叠加纹理与颜色渐变。
  • 物理模拟填充​:如液体扩散效果,需引入噪声函数与时间变量。

二、核心算法实现

2.1 颜色插值原理

2.1.1 线性插值公式
float ratio = currentPos / totalLength;  
float r = rStart * (1 - ratio) + rEnd * ratio;  

应用场景​:

  • 顶点渐变:按顶点位置权重插值
  • 扫描线动画:按扫描线位置插值
2.1.2 扫描线填充算法
for (int y = startY; y < endY; y++) {
    float lineRatio = (y - startY) / (float)(endY - startY);
    // 根据lineRatio计算当前行颜色
}

优化技巧​:

  • 使用整数运算代替浮点运算提升性能
  • 预计算颜色梯度表减少重复计算

三、代码架构解析

3.1 系统模块划分

class FillSystem {
public:
    void initPolygon();        // 初始化测试多边形
    void drawSolid();          // 纯色填充模式
    void drawGradient();       // Gouraud着色模式
    void drawScanline();       // 扫描线动画模式
private:
    std::vector<std::pair<float,float>> vertices; // 多边形顶点
    float colorStart[3];       // 起始颜色RGB
    float colorEnd[3];         // 终止颜色RGB
    float animationProgress;   // 动画进度(0.0~1.0)
};

3.2 关键代码实现

3.2.1 顶点渐变填充
void drawGradient() {
    glBegin(GL_POLYGON);
    for (size_t i = 0; i < vertices.size(); ++i) {
        // 计算顶点间颜色插值
        float ratio = i / (float)(vertices.size()-1);
        glColor3f(
            colorStart[0]*(1-ratio) + colorEnd[0]*ratio,
            colorStart[1]*(1-ratio) + colorEnd[1]*ratio,
            colorStart[2]*(1-ratio) + colorEnd[2]*ratio
        );
        glVertex2f(vertices[i].first, vertices[i].second);
    }
    glEnd();
}

技术亮点​:

  • 使用GL_SMOOTH着色模式启用顶点插值
  • 线性插值保证颜色过渡平滑
3.2.2 扫描线动画实现
void drawScanline() {
    int currentLine = animationProgress * H;  
    for (int y = -H/2; y < -H/2 + currentLine; ++y) {
        // 计算垂直方向颜色渐变
        float ratio = (y + H/2) / (float)H;  
        glColor3f(
            colorStart[0]*(1-ratio) + colorEnd[0]*ratio,
            colorStart[1]*(1-ratio) + colorEnd[1]*ratio,
            colorStart[2]*(1-ratio) + colorEnd[2]*ratio
        );
        // 绘制水平扫描线
        glBegin(GL_LINES);
            glVertex2f(-100, y);
            glVertex2f(100, y);
        glEnd();
    }
}

性能优化​:

  • 限制最大绘制行数为窗口高度
  • 使用批量绘制减少状态切换

四、关键技术详解

4.1 双缓冲动画机制

void timerFunc(int value) {
    animationProgress += 0.005f;  
    if (animationProgress > 1.0f) animationProgress = 0.0f;
    glutPostRedisplay();  // 触发双缓冲交换
    glutTimerFunc(16, timerFunc, 0);  
}

工作原理​:

  1. 前缓冲:显示当前帧
  2. 后缓冲:绘制下一帧
  3. 帧完成后交换缓冲

4.2 颜色空间管理

// RGB颜色存储结构(C++98兼容写法)
struct Color {
    float r, g, b;
    Color(float r=0, float g=0, float b=0) : r(r), g(g), b(b) {}
    Color interpolate(const Color& end, float t) const {
        return Color(
            r*(1-t) + end.r*t,
            g*(1-t) + end.g*t,
            b*(1-t) + end.b*t
        );
    }
};

扩展性​:

  • 支持HSV颜色空间转换
  • 可添加透明度通道

五、功能扩展方向

5.1 填充模式增强

扩展功能实现方案技术难点
纹理映射填充加载位图纹理并映射到多边形纹理坐标计算与UV展开
模式混合填充多种填充模式叠加Alpha通道混合计算
动态渐变路径沿任意路径进行颜色渐变路径参数化与积分计算

5.2 交互功能升级

// 添加颜色选择对话框(Windows API)  
COLORREF selectedColor = ChooseColor(colorDialog);  
glColor3f(
    GetRValue(selectedColor)/255.0f,
    GetGValue(selectedColor)/255.0f,
    GetBValue(selectedColor)/255.0f
);

实现要点​:

  • 将RGB值从[0,255]转换到[0,1]区间
  • 支持颜色拾取器交互

六、完整代码

// ===================================================================
// 文件名:SimpleFiller_Cpp98.cpp
// 功能:简单图形填充器,支持纯色、顶点渐变和扫描线渐变动画
// 编译(Dev-C++ 4.9.2 32-bit)链接:
//   -lopengl32 -lglu32 -lglut32 -lwinmm -lgdi32
// ===================================================================
#define GLUT_DISABLE_ATEXIT_HACK
#include <windows.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
#include <vector>
#include <utility>  // std::pair, std::make_pair
#include <cmath>

// 窗口尺寸
const int W = 800;
const int H = 600;

// 渐变进度 [0,1]
float t = 0.0f;
const float dt = 0.005f;  // 每帧增量

// 颜色起始与终止(可根据需要修改)
float r1 = 1.0f, g1 = 0.0f, b1 = 0.0f;  // 红色起始
float r2 = 0.0f, g2 = 0.0f, b2 = 1.0f;  // 蓝色结束

// 多边形顶点(正方形),使用 std::vector 和 std::pair<C++98 写法>
std::vector< std::pair<float, float> > poly;

// 模式切换
bool showSolid   = false;
bool showGouraud = true;
bool showScan    = false;

// -------------------------------------------------------------------
// 初始化多边形顶点
void initPoly() {
    poly.clear();
    poly.push_back(std::make_pair(-100.0f, -100.0f));
    poly.push_back(std::make_pair( 100.0f, -100.0f));
    poly.push_back(std::make_pair( 100.0f,  100.0f));
    poly.push_back(std::make_pair(-100.0f,  100.0f));
}

// -------------------------------------------------------------------
// OpenGL 初始化
void initGL(){
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);  // 白背景
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(-W/2, W/2, -H/2, H/2);
}

// -------------------------------------------------------------------
// 纯色填充
void drawSolid(){
    glColor3f(r1, g1, b1);
    glBegin(GL_POLYGON);
    for (size_t i = 0; i < poly.size(); ++i) {
        glVertex2f(poly[i].first, poly[i].second);
    }
    glEnd();
}

// -------------------------------------------------------------------
// 顶点渐变填充 (Gouraud)
// 利用顶点颜色插值
void drawGradient(){
    glShadeModel(GL_SMOOTH);
    glBegin(GL_POLYGON);
    size_t n = poly.size();
    for (size_t i = 0; i < n; ++i) {
        float ratio = float(i) / float(n - 1);
        float rc = r1 * (1 - ratio) + r2 * ratio;
        float gc = g1 * (1 - ratio) + g2 * ratio;
        float bc = b1 * (1 - ratio) + b2 * ratio;
        glColor3f(rc, gc, bc);
        glVertex2f(poly[i].first, poly[i].second);
    }
    glEnd();
}

// -------------------------------------------------------------------
// 扫描线渐变动画
void drawScanline(){
    int totalLines = H;
    int currentLine = int(t * totalLines);
    for (int y = -H/2; y < -H/2 + currentLine; ++y) {
        float ratio = float(y + H/2) / float(totalLines);
        float rc = r1 * (1 - ratio) + r2 * ratio;
        float gc = g1 * (1 - ratio) + g2 * ratio;
        float bc = b1 * (1 - ratio) + b2 * ratio;
        glColor3f(rc, gc, bc);
        glBegin(GL_LINES);
        glVertex2f(-100.0f, (float)y);
        glVertex2f( 100.0f, (float)y);
        glEnd();
    }
}

// -------------------------------------------------------------------
// 显示回调
void display(){
    glClear(GL_COLOR_BUFFER_BIT);

    if (showSolid) {
        drawSolid();
    }
    if (showGouraud) {
        drawGradient();
    }
    if (showScan) {
        drawScanline();
    }

    glutSwapBuffers();
}

// -------------------------------------------------------------------
// 定时器:更新 t 并重绘
void timerFunc(int value){
    t += dt;
    if (t > 1.0f) t = 0.0f;
    glutPostRedisplay();
    glutTimerFunc(16, timerFunc, 0);  // ~60 FPS
}

// -------------------------------------------------------------------
// 键盘回调:切换模式
void keyboard(unsigned char key, int x, int y){
    switch (key) {
        case '1':
            showSolid   = true;
            showGouraud = showScan = false;
            break;
        case '2':
            showGouraud = true;
            showSolid = showScan = false;
            break;
        case '3':
            showScan    = true;
            showSolid = showGouraud = false;
            break;
        case 27: // ESC
            exit(0);
            break;
        default:
            break;
    }
}

// -------------------------------------------------------------------
// 主函数
int main(int argc, char** argv){
    initPoly();

    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
    glutInitWindowSize(W, H);
    glutInitWindowPosition(100, 100);
    glutCreateWindow("Simple Shape Filler (C++98)");

    initGL();

    glutDisplayFunc(display);
    glutKeyboardFunc(keyboard);
    glutTimerFunc(0, timerFunc, 0);

    glutMainLoop();
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值