用C++画出一片樱花林(来源于我的一篇大作业)

樱花林

2.选题分析

  1. 樱花树的生成和生长
    • 树木结构模拟:使用递归或L系统(Lindenmayer系统)等算法来模拟树木的生长过程。L系统是一种递归的字符串替换系统,用于模拟植物的生长规律。
    • 树干和分支的生成:确定树木的分支模式、生长方向、长度和角度。可以考虑增加一些随机性,以增强树木的真实感。
    • 生长动画:实现生长过程中树木结构的动态变化,从树冠到树干逐渐生成,并考虑模拟枝条的扭曲和变化。
  2. 樱花花朵的绘制和绽放
    • 花朵的外观:设计花朵的形状、颜色和纹理。樱花的花瓣一般为淡粉色或白色,可以考虑使用贴图或基本形状来实现。
    • 绽放过程:通过逐渐改变花朵的大小、颜色和透明度来模拟花朵的绽放。可以结合缓慢的动画效果和渐变来实现。
  3. 场景的绘制和渲染
    • 地面和背景:绘制樱花林的背景、草地或其他植被,并考虑增加自然元素如小溪或其他树木。
    • 光照和阴影效果:考虑使用基本的光照模型和阴影算法增强场景的真实感。
  4. 性能优化和扩展
    • 数据结构优化:选择合适的数据结构来表示树木、花朵和场景,以提高渲染效率。
    • 多线程或并行处理:考虑使用多线程技术来加速生成和渲染复杂的樱花林场景。
  5. 美学和细节
    • 动画和渐变效果:利用平滑的动画和过渡效果增强樱花林的视觉吸引力。
    • 音效和氛围:考虑添加背景音乐或环境音效,增强用户体验。

2.思路流程

  1. 1. 明确生成樱花树的原理

    • #define PI 3.1415926
      #define WIDTH 1000
      #define HEIGHT 600
      
      float offsetAngle = PI / 6;
      float shorn = 1;:枝干的偏移角度,枝干的缩短速率。
      
      • isShowAnimation 是控制是否显示动画,1则为显示樱花生成动画
    • void branch(float x_start, float y_start, float length, float angle, float thickness, int generation) {
             
          float x_end, y_end; // 存储枝干结束坐标
          x_end = x_start + length * cos(angle); // 根据角度计算结束坐标x
          y_end = y_start + length * sin(angle); // 根据角度计算结束坐标y
      
          setlinestyle(PS_SOLID, thickness);      // 设定当前枝干线宽
          COLORREF color = HSVtoRGB(15, 0.75, 0.4 + generation * 0.05); // 枝干颜色  参数分别对应于色相(Hue)、饱和度(Saturation)和值(Value)。
          setlinecolor(color); // 设置枝干颜色
      
          line(x_start, y_start, x_end, y_end); // 绘制枝干
      
          int childGeneration = generation + 1;   // 子枝干的代数
          float childLength = shortenRate * length; // 子枝干的长度逐渐变短
          float leftChildLength = childLength * randBetween(0.9, 1.1);  // 为子枝干长度引入随机性
          float rightChildLength = childLength * randBetween(0.9, 1.1);
          float centerChildLength = childLength * randBetween(0.8, 1.1);
      
      • 函数参数

        • x_start:表示分支的起始 x 坐标。
        • y_start:表示分支的起始 y 坐标。
        • length:表示分支的长度。
        • angle:指定分支延伸的角度或方向。
        • thickness:表示树枝的粗细或宽度。
        • generation:指示递归结构中分支的生成或级别。此参数可用于控制分支行为或递归终止。
      • setlinestyle是图形库或框架中常见的一种函数或方法,它允许开发人员设置绘制线条的样式。但是,此函数/方法的确切用法和实现可能因所使用的特定编程语言或图形库而异。

      • PS_SOLID是一个值,可用于在 Windows 环境中绘图时指定笔或线条的样式。具体来说,它表示坚实的笔风格。在 WinAPI 的 GDI(图形设备接口)的上下文中使用时,它表示一种笔样式,该样式绘制实线,没有任何特殊图案或短划线。

      • COLORREF是 Windows 编程中使用的数据类型,它代表“颜色参考”。

      • HSVtoRGB(15, 0.75, 0.4 + generation * 0.05)从 HSV(色相、饱和度、值)颜色空间到 RGB(红、绿、蓝)颜色空间的转换。此转换可能会根据特定的 HSV 参数生成 RGB 颜色,根据其值按百分比 () 递增亮度来调整亮度(值分量)

      • line(x_start, y_start, x_end, y_end);常规的Easyx库中生成线条函数

      • randBetween是一个生成随机数函数,来随机确定子代树干长度

        float randBetween(float min, float max)
        {
                 
            float t = rand() / double(RAND_MAX);      // 生成[0, 1]的随机小数
            float r = mapValue(t, 0, 1, min, max);    // 利用mapValue函数映射随机数到[min, max]
            return r;
        }
        
      • float mapValue(float input, float inputMin, float inputMax, float outputMin, float outputMax)
        {
                 
            float output;
            if (fabs(input - inputMin) < 0.000001)   // 防止除0
            {
                 
                output = outputMin;
            }
            else
            {
                 
                output = (input - inputMin) * (outputMax - outputMin) / (inputMax - inputMin) + outputMin; // 映射函数
            }
            return output;
        }
        
      • mapValue函数用于将值从一个范围映射或缩放到另一个范围的函数。此函数接受输入值并将其从输入范围 ( 到 ) 缩放到输出范围 ( 到 )

        • 参数细分
          • input:从输入范围映射到输出范围的值。
          • inputMin:输入范围的最小值。
          • inputMax:输入范围的最大值。
          • outputMin:输出范围的最小值。
          • outputMax:输出范围的最大值。
        • 该函数使用线性插值将输入值从输入范围映射到输出范围,并通过在执行计算之前检查输入是否非常接近来防止除以零。
        • 完成映射的分步说明:
          • 如果 和 之间的绝对差极小(小于 ),则函数设置为 以防止在计算输出时可能除以零误差。input``inputMin``0.000001``output``outputMin
          • 否则,它应用线性插值,使用以下公式将输入值从输入范围 ( to ) 映射到输出范围 ( to ):inputMin``inputMax``outputMin``outputMax
          • 输出=(inputMax−inputMin输入−输入最小值 )×(输出最大−输出最小值)+输出最小值 该公式计算输入范围内的比例值,并将其映射到输出范围内的相应值。input
          • 此函数的目的是将值从一个范围重新缩放或映射到另一个范围,确保输入值在定义的范围内,并按比例将其映射到新的值范围。
      •     if (childLength >= 2 && childGeneration <= 9)               // 当子枝干长度大于2,且代数小于等于9,绘制子枝干
            {
                 
                float childThickness = thickness * 0.8;                 // 枝干逐渐变细
                if (childThickness < 2)
                {
                 
                    childThickness = 2;
                }
        
                if (randBetween(0, 1) < 0.95)
                {
                 
                    branch(x_end, y_end, leftChildLength, angle + offsetAngle * randBetween(0.5, 1), childThickness, childGeneration); // 递归绘制左侧子枝干
                }
                if (randBetween(0, 1) < 0.95)
                {
                 
                    branch(x_end, y_end, childLength, angle - offsetAngle * randBetween(0.5, 1), childThickness, childGeneration); // 递归绘制右侧子枝干
                }
                if (randBetween(0, 1) < 0.85)
                {
                 
                    branch(x_end, y_end, centerChildLength, angle + offsetAngle / 5 * randBetween(-1, 1), childThickness, childGeneration); // 递归绘制中间子枝干
                }
            }
            else
            {
                 
                setlinestyle(PS_SOLID, 1); // 恢复默认线型
                COLORREF color = HSVtoRGB(randBetween(300, 350), randBetween(0.2, 0.3), 1); // 生成花朵颜色
                setlinecolor(color); // 设置花朵颜色
                setfillcolor(color); // 设置花朵填充颜色
                if (childLength <= 4)
                {
                 
                    fillcircle(x_end, y_end, 2); // 根据长度绘制小花朵
                }
                else
                {
                 
                    fillcircle(x_end, y_end, childLength / 2); // 根据长度绘制大花朵
                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值