尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

openFrameworks periodicSignalsExample 详解:用正弦、噪声、随机与取模绘制周期信号

发布时间:2026/9/24 14:21:31

资讯中心
01
ARTICLE

openFrameworks periodicSignalsExample 详解:用正弦、噪声、随机与取模绘制周期信号

openFrameworks periodicSignalsExample 详解:用正弦、噪声、随机与取模绘制周期信号
图形学音视频【免费下载链接】openFrameworksopenFrameworks is a community-developed cross platform toolkit for creative coding in C.项目地址https://gitcode.com/gh_mirrors/op/openFrameworks点击查看免费下载导读periodicSignalsExample是 openFrameworks 官方示例库中位于examples/math/目录下的一个教学示例它用 8 条水平移动的轨迹直观对比了四类周期信号生成方式三角函数sin、柏林噪声ofNoise/ofSignedNoise、真随机ofRandom以及浮点取模fmod。通过阅读本文你将掌握这些信号函数在 openFrameworks 中的底层实现与取值范围差异理解“随机 ≠ 噪声”“伪随机噪声带缓动”的核心区别并学会用滑块实时调整振幅、速度与频率来观察每种信号的形态特征。这对于制作粒子系统、运动动画、程序化生成等创意编码场景都极具参考价值。示例概述与运行方式本示例的完整源码位于 examples/math/periodicSignalsExample核心文件为 ofApp.cpp 与 ofApp.h另附带一个自定义的 ofxSimpleSlider 滑块控件由 Golan Levin 于 2012 年编写。窗口尺寸在 main.cpp 中设置为1024 x 600标准窗口模式OF_WINDOW。应用启动后画面上会出现8 条水平移动的轨迹每条轨迹对应一种不同的周期信号函数右侧标注有函数名称。底部的时间轴刻度以秒s或像素p为单位标记当前 x 位置右上角实时显示帧率fps、运行时间t与当前 x 坐标便于对照观察。八种周期信号的核心实现在 ofApp.cpp 的update()中示例以运行时间t通过ofGetElapsedTimef()获取并减去初始时间得到作为输入为每条轨迹计算y值。时间变量t的求法为t ofGetElapsedTimef(); if(trail[0].size()0){ initTime t; } t t - initTime;而水平位置x由速度滑块的值与时间共同决定并取模限制在窗口宽度内x int(t*speed.getValue())%(ofGetWidth()-rightMargin);1. constant —— 常量基线y[0] 60*2;在setup()中直接赋值为常量代表一条水平的直线基线用于与其他波动信号形成参照。2. ofNoise(t) —— 柏林噪声0 ~ 1y[1] 60*3ofNoise(t*freq.getValue())*yFactor.getValue();ofNoise()基于柏林噪声Perlin noise算法返回0 到 1.0 之间的连续伪随机值。查看 ofMath.cpp 的底层实现可以看到float ofNoise(float x) { return _slang_library_noise1(x) * 0.5f 0.5f; }它先调用底层的_slang_library_noise1()值域约为 -1 ~ 1再通过* 0.5 0.5映射到 [0, 1] 区间。所谓“伪随机带缓动”是指噪声函数在相邻输入之间会产生平滑过渡的渐变值而非毫无关联的跳变因此适合模拟自然、有机的运动。3. ofSignedNoise(t) —— 带符号噪声-1 ~ 1y[2] 60*4ofSignedNoise(t*freq.getValue())*yFactor.getValue();ofSignedNoise()与ofNoise()共享同一个噪声内核但不做 0.5 偏移直接返回原始噪声值值域为-1.0 到 1.0float ofSignedNoise(float x) { return _slang_library_noise1(x); }两者对比如下函数底层调用值域用途特点ofNoise(x)_slang_library_noise1(x) * 0.5f 0.5f[0, 1]适合 alpha、比例等非负参数ofSignedNoise(x)_slang_library_noise1(x)[-1, 1]适合位移、旋转等对称变化在 ofMath.h 中两者都提供了 1~4 维重载分别接受float、glm::vec2、glm::vec3、glm::vec4参数。4. ofRandom(-1,1) —— 真随机-1 ~ 1y[3] 60*5ofRandom(-1,1)*yFactor.getValue(); // random cant be dependent on time or frequencyofRandom(min, max)返回 min 与 max 之间完全随机的浮点数每次调用结果彼此独立、没有连续性。其实现见 ofMath.cppfloat ofRandom(float min, float max) { return of::random::uniformfloat(min, max); }ofRandom与噪声函数有着本质区别噪声是伪随机但连续相邻值平滑过渡而ofRandom是完全不连续的跳跃值。因此示例代码特意注释“random cant be dependent on time or frequency”——由于随机值不受时间与频率影响这条轨迹看起来会不断跳变无法形成平滑的波形。5. sin(t) —— 标准正弦波-1 ~ 1y[4] 60*6 std::sin(t*freq.getValue()*glm::two_pifloat())*yFactor.getValue();这是最经典的周期信号。glm::two_pifloat()即 2π将时间乘以 2π 后每经过 1 秒恰好完成一个完整的正弦周期频率滑块的值单位 Hz直接决定每秒的振荡次数。返回值在-1 到 1 之间平滑往返。6. (sin(t)1)/2 —— 正弦波归一化0 ~ 1y[5] 60*7(std::sin(t*freq.getValue()*glm::two_pifloat())1)*.5*yFactor.getValue();将标准正弦结果1后除以 2把值域从 [-1, 1] 线性映射到[0, 1]方便驱动透明度、颜色分量等非负参数。从源码结构看这与ofNoise对底层噪声做* 0.5 0.5映射的思路如出一辙。7. fmod(t, 1) —— 浮点取模0 ~ 1y[6] 60*8std::fmod(t*freq.getValue(),1)*yFactor.getValue();std::fmod(a, b)返回 a 除以 b 的浮点余数。fmod(t, 1)的输出始终落在[0, 1)波形呈锯齿状每经过 1 个时间单位归零并重新攀升。它与整数取模运算符%语义相同但专门用于浮点数——这正是 README 中强调fmod“is the same as using %; however, it is for floats”的原因。8. fmod(t, 1)*2-1 —— 双锯齿波-1 ~ 1y[7] 60*9(std::fmod(t*freq.getValue(),1)*2-1)*yFactor.getValue();在fmod(t, 1)的基础上乘以 2 再减 1将值域映射到[-1, 1]形成上下对称的双向锯齿波。滑块实时控制振幅、速度与频率三个滑块的配置在setup()中创建了三个 ofxSimpleSlider 实例分别控制垂直振幅y amnt、水平速度x speed与频率frequencyyFactor.setup(130, 20, 100, 20, 0, 100, 20, false, false); yFactor.setLabelString(y amnt); speed.setup(130, 45, 100, 20, 1, 200, 30, false, false); speed.setLabelString(x speed (px/s)); freq.setup(130, 70, 100, 20, 0, 10, 1, false, false); freq.setLabelString(frequency (hz));setup()的完整参数签名为setup(float inx, float iny, float inw, float inh, float loVal, float hiVal, float initialPercent, bool bVert, bool bDrawNum)前 4 个参数是滑块的位置与尺寸loVal/hiVal是取值范围initialPercent为初始值内部通过ofMap映射为百分比并ofClamp到 [0,1]bVert表示是否垂直放置bDrawNum表示是否绘制数值。本例三个滑块均水平放置、不显示数值。各滑块参数汇总滑块标签取值范围默认值作用yFactory amnt0 ~ 10020信号的振幅垂直幅度speedx speed (px/s)1 ~ 20030轨迹的水平滚动速度像素/秒freqfrequency (hz)0 ~ 101信号的频率每秒周期数滑块的底层实现ofxSimpleSlider是一个不依赖任何 addon 的轻量滑块类其核心机制是setup()时通过ofAddListener把自己注册到ofEvents()的draw、mouseMoved、mousePressed、mouseReleased、mouseDragged事件上见 ofxSimpleSlider.cpp此后无需在ofApp中手动转发事件。拖拽时updatePercentFromMouse()把鼠标坐标映射为 0~1 的百分比void ofxSimpleSlider::updatePercentFromMouse (int mx, int my){ if (bVertical){ percent ofMap(my, y, yheight, 1,0, true); } else { percent ofMap(mx, x, xwidth, 0,1, true); } }读取当前值时再由百分比反向映射到loVal与hiVal之间float ofxSimpleSlider::getValue(){ // THIS IS THE MAIN WAY YOU GET THE VALUE FROM THE SLIDER! float out ofMap(percent, 0,1, lowValue,highValue, true); return out; }速度变化的轨迹清空机制update()中对速度变化做了特殊处理由于不能直接比较浮点数的相等性speed.getValue() ! preSpeed不可靠示例改用“变化量大于极小阈值”的方式检测if( fabs(speed.getValue() - preSpeed) 0.00001f ){ speedChanged(); } preSpeed speed.getValue();一旦速度改变speedChanged()会清空所有轨迹折线避免不同速度下的轨迹在同一个 x 轴上错位重叠void ofApp::speedChanged(){ for(unsigned int i0;itrail.size();i){ trail[i].clear(); } }此外由于x int(t*speed) % (ofGetWidth()-rightMargin)存在取模回绕当x小于上一帧的prevX时即发生回绕也会主动清空轨迹形成“换行重画”的效果for(int i0;i(int)trail.size();i){ if(xprevX){ trail[i].clear(); }else{ trail[i].addVertex(x,y[i]); } } prevX x;绘制细节轨迹、网格与标签draw()见 ofApp.cpp完成了以下绘制工作渐变背景使用ofBackgroundGradient(ofColor(240), ofColor(210), OF_GRADIENT_BAR)生成从浅灰到中灰的垂直渐变时间刻度线在左侧区域按speed值绘制垂直虚线底部标注以秒s或像素p为单位的刻度showPos布尔值控制刻度单位显示8 条轨迹每条轨迹用一个ofPolyline存储顶点序列并调用trail[i].draw()绘制轨迹头部绘制一个半径为 3 的圆点ofDrawCircle(x, y[i], radius)绘制时启用ofEnableSmoothing()抗锯齿绘制后关闭分隔线每条轨迹之间以水平直线分隔每条轨迹 60 像素的垂直间距右侧标签在右侧预留的 190 像素边距rightMargin 190内用ofDrawBitmapString标注每条轨迹对应的函数名例如constant、ofNoise(t)、ofSignedNoise(t)、ofRandom(-1,1)、sin(glm::two_pifloat()*t)、(sin(glm::two_pifloat()*t)1)/2、modulo(t,1)、modulo(t,1)*2-1状态信息右上角实时显示fps、运行时间t与当前位置x振幅指示每个轨迹右侧绘制一条从分隔线到当前y值的小矩形直观表示振幅大小。操作指南与关键注意事项交互方式应用运行后用鼠标直接拖拽右侧三个滑块即可实时调节y amnt振幅控制所有信号轨迹的垂直摆动幅度范围为 0 ~ 100x speed (px/s)速度控制轨迹水平滚动的速度范围为 1 ~ 200 像素/秒改变速度会触发轨迹清空重绘frequency (hz)频率控制每种周期信号的振荡频率范围为 0 ~ 10 Hz。需要特别注意的点ofRandom不依赖时间与频率由于随机值每次调用都是独立跳变改变频率滑块对它没有平滑效果这正是随机信号与噪声、三角函数最直观的差异。噪声 ≠ 随机ofNoise/ofSignedNoise是连续平滑的伪随机缓动适合有机运动ofRandom是离散跳变适合无规律的抖动。浮点比较陷阱不要用/!直接比较浮点滑块值应像示例那样使用阈值判断fabs(a - b) 0.00001f。值域决定用途0~1 的信号ofNoise、(sin1)/2、fmod(t,1)适合驱动比例类参数-1~1 的信号ofSignedNoise、sin、ofRandom(-1,1)、fmod(t,1)*2-1适合驱动位移、旋转等双向变化。延伸阅读三角函数专题examples/math/trigonometryExample与examples/math/trigonometricMotionExample后者同样位于 examples/mathREADME 中对三角函数的推荐深入阅读随机与噪声的更多组合玩法noise1dExample、noise1dOctaveExample、noiseField2dExample 与 randomExample运动应用实战particlesExample 展示了如何将周期与噪声信号用于粒子系统底层数学实现ofNoise/ofSignedNoise/ofRandom等函数的源码位于 libs/openFrameworks/math/ofMath.cpp 与 libs/openFrameworks/math/ofMath.h。通过运行本示例并拖动三个滑块你可以直观地感受到“平滑周期”“平滑伪随机”“离散随机”“锯齿周期”四类信号的形态差异——这是理解 openFrameworks 运动与生成式创作的重要基础。赞分享图形学音视频【免费下载链接】openFrameworksopenFrameworks is a community-developed cross platform toolkit for creative coding in C.项目地址https://gitcode.com/gh_mirrors/op/openFrameworks点击查看免费下载相关推荐GNU Radio信号源模块终极指南如何快速生成随机噪声、正弦波和方波信号GNU Radio信号源模块终极指南如何快速生成随机噪声、正弦波和方波信号 想要在GNU Radio中快速生成各种信号吗GNU Radio作为免费开源的软件通信科研Easy Effects 测试信号Test Signal完全指南用正弦波与噪声信号测量音箱频响Easy Effects 测试信号Test Signal完全指南用正弦波与噪声信号测量音箱频响 Easy Effects 内置的 Test Signal桌面应用音频处理Agent OS 信号处理机制详解用 POSIX 风格信号实现 AI Agent 生命周期治理Agent OS 信号处理机制详解用 POSIX 风格信号实现 AI Agent 生命周期治理 Agent OSagent governance toolk人工智能AI AgentAI 安全治理策略引擎Agent 沙箱认证鉴权上一篇VnCoreNLP二次开发指南自定义annotator扩展越南语NLP流水线下一篇超强大屏体验iCarousel打造iOS/MacOS双平台3D轮播组件创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。