免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

openFrameworks vectorMathExample 实战指南:用 glm::vec3 与自定义形状实现矢量绘图与 3D 旋转

openFrameworks vectorMathExample 实战指南:用 glm::vec3 与自定义形状实现矢量绘图与 3D 旋转 图形学音视频【免费下载链接】openFrameworksopenFrameworks is a community-developed cross platform toolkit for creative coding in C.项目地址https://gitcode.com/gh_mirrors/op/openFrameworks点击查看免费下载导读vectorMathExample是 openFrameworks 官方examples/math目录下的一个入门级数学示例它的核心目的只有一个用最直观的方式展示「矢量vector到底是什么」以及「如何用矢量来绘图」。在这个示例里你按住鼠标拖动即可在屏幕上画线而存储每一笔轨迹的数据结构就是glm::vec3数组程序还会自动让整条轨迹绕屏幕中心旋转并允许你用键盘实时调节旋转速度与旋转轴。读完本文你将掌握glm::vec3的基本用法、ofBeginShape()/ofVertex()/ofEndShape()自定义形状绘制流程以及「平移—旋转—平移回来」这一 3D 数学变换的经典套路并能在自己的 openFrameworks 工程中复现这套交互。示例概况与文件结构该示例位于 examples/math/vectorMathExample源码结构非常精简src/main.cpp创建 1024×768 的窗口并启动应用src/ofApp.h声明点数组、旋转参数、坐标轴端点等成员src/ofApp.cpp实现 setup / update / draw 以及全部鼠标键盘交互。main.cpp 使用ofGLWindowSettings设置窗口尺寸为 1024×768、窗口模式为OF_WINDOW然后通过ofCreateWindow与ofRunApp启动应用这是当前版本 openFrameworks 的标准启动写法。核心数据结构glm::vec3 点数组在 ofApp.h 中示例用两个关键成员承载整个程序的状态#define MAX_N_PTS 1500 glm::vec3 pts[MAX_N_PTS]; // 存储用户画下的每一个点 int nPts; // 当前已存储的点数 glm::vec3 rotateAmount; // 绕 x/y/z 三个轴的旋转量 float speedOfRotation; // 每帧旋转的角度glm::vec3是 openFrameworks 内置的 GLM 数学库提供的三维矢量类型每个矢量包含x、y、z三个分量。正如 README 中所强调的一个矢量在抽象的空间里同时代表方向和大小magnitude。本示例中它被当作「点的坐标」来使用同时也被用来描述「旋转轴」。MAX_N_PTS是点的容量上限1500 个这个上限同时在mouseDragged中被检查保证pts[nPts]永远不会越界写入。数组的写入方式也很典型pts[nPts].x x; pts[nPts].y y; nPts;即通过下标nPts定位到数组中的特定位置逐分量赋值再自增计数器。鼠标绘制存储轨迹点绘制交互集中在 ofApp.cppmouseDragged每拖动一次就向pts数组中追加一个点上限MAX_N_PTS并置bDrawnAnything true这样屏幕上会随之显示提示文字mousePressed把nPts归零实现「单击一次清屏」。void ofApp::mouseDragged(int x, int y, int button){ bDrawnAnything true; if (nPts MAX_N_PTS){ pts[nPts].x x; pts[nPts].y y; nPts; } }这是典型的「采样式」轨迹记录把鼠标的实时坐标(x, y)按序存入数组后续的旋转、绘制都基于这份点序列进行。自定义形状绘制ofBeginShape → ofVertex → ofEndShapedraw()中先用ofBeginShape()开启一段新的形状然后遍历所有点调用ofVertex(pts[i].x, pts[i].y)最后以ofEndShape()结束ofSetHexColor(0x000000); ofNoFill(); ofBeginShape(); for (int i 0; i nPts; i){ ofVertex(pts[i].x, pts[i].y); } ofEndShape();在 ofGraphics.h 中这三个 API 的契约非常明确ofBeginShape()开始绘制一个新的形状之后必须跟一串顶点最后调用ofEndShape()ofVertex(...)在ofBeginShape()与ofEndShape()之间指定形状上的单个点除(x, y)、(x, y, z)两个重载外还支持直接传入glm::vec3/glm::vec2ofEndShape(bool bClose false)结束形状并绘制到屏幕必须调用否则看不到形状参数bClose为 true 时自动闭合形状默认 false即不闭合。这段代码配合ofNoFill()只描边不填充于是用户拖出的轨迹被渲染成一条连续的黑线。类似的形状 API 还有ofCurveVertex曲线顶点、ofBezierVertex贝塞尔顶点、ofVertices批量顶点等均需在ofBeginShape()/ofEndShape()之间使用。三轴旋转参考线为了让用户直观感受到旋转setup()中定义了 x/y/z 三条坐标轴的端点各 100 个单位长并平移到窗口中心glm::vec3 center(ofGetWidth()/2, ofGetHeight()/2, 0); xAxisMin {-100, 0, 0}; xAxisMax { 100, 0, 0}; yAxisMin { 0,-100, 0}; yAxisMax { 0, 100, 0}; zAxisMin { 0, 0,-100}; zAxisMax { 0, 0, 100}; xAxisMin center; // ... 其余端点同样 centerdraw()里用三组ofBeginShape()/ofVertex(x, y, z)/ofEndShape()分别绘制三条轴线颜色为ofSetColor(50,50,255)的蓝色。由于视角正对 z 轴z 分量在屏幕上不可见所以默认只能看到 x、y 两条轴——这正是 README 所说的只有 x 和 y 轴可见。3D 旋转变换平移—旋转—平移回去update()是整个示例的数学核心。由于glm::rotate是绕原点 (0,0,0) 旋转而屏幕坐标系的原点在左上角所以直接旋转会导致轨迹绕角落打转。示例用注释把标准流程拆成了三步ofApp.cpp// (A) 平移到原点把每个点减去中心坐标 for (int i 0; i nPts; i){ pts[i] - center; } // (B) 旋转glm::rotate(vec, angle, axis) for (int i 0; i nPts; i){ pts[i] glm::rotate(pts[i], speedOfRotation, rotateAmount); } // (C) 平移回来把每个点加回中心坐标 for (int i 0; i nPts; i){ pts[i] center; }glm::rotate(vec, angle, axis)会返回绕axis轴旋转angle弧度后的新矢量。同样的三步变换也应用在三条坐标轴的 6 个端点上保证轴线与轨迹同步旋转。setup()中的初始值rotateAmount {0, 0, 1}; // 默认绕 z 轴旋转 speedOfRotation ofDegToRad(0.5f); // 每帧 0.5 度换算为弧度ofDegToRad(0.5f)把 0.5 度转成弧度作为每帧旋转角初始旋转轴为 z 轴。键盘交互实时调节旋转keyPressedofApp.cpp用 switch 处理 8 个按键规则与 README 完全一致按键作用增量a/z增加 / 减小旋转速度speedOfRotation±0.001 弧度s/x增加 / 减小 x 方向旋转量rotateAmount.x±0.05d/c增加 / 减小 y 方向旋转量rotateAmount.y±0.05f/v增加 / 减小 z 方向旋转量rotateAmount.z±0.05case a: speedOfRotation 0.001f; break; case s: rotateAmount.x 0.05f; break; // ... 其余按键同理改变rotateAmount的各分量相当于改变旋转轴的朝向——例如把rotateAmount设为{1, 0, 0}并减小 z 分量轨迹就会从绕屏幕平面旋转变为绕水平轴翻转。注意旋转轴矢量无需归一化GLM 内部会自行处理但各分量的相对比例决定了轴向。HUD 信息面板draw()的末尾绘制了一个芥末黄0xE5A93F信息面板实时显示旋转速度与三轴旋转量string info speed of rotation (a/z): ofToString(speedOfRotation,3) \n rotateAmount in x (s/x): ofToString(rotateAmount.x,3) \n rotateAmount in y (d/c): ofToString(rotateAmount.y,3) \n rotateAmount in z (f/v): ofToString(rotateAmount.z,3); ofFill(); ofSetHexColor(0xE5A93F); ofDrawRectangle(10,10,300,70); ofSetHexColor(0x000000); ofDrawBitmapString(info,30,30);ofToString(value, 3)将浮点数保留 3 位小数输出面板由ofDrawRectangle画底、ofDrawBitmapString写字组成。另外若用户尚未画过任何东西bDrawnAnything false屏幕中央会显示 draw something! 提示。运行与体验运行该示例的方式与 openFrameworks 其他示例一致在 examples/math/vectorMathExample 目录下使用 openFrameworks 项目生成器Project Generator生成对应平台工程后编译运行或直接通过of命令行工具构建。启动后按住鼠标左键并拖动即可画出一条连续的黑色轨迹轨迹顶点被实时存入pts数组轨迹与蓝色坐标轴会绕窗口中心持续旋转默认绕 z 轴每帧 0.5 度按a/z调节旋转速度按s/x、d/c、f/v分别调节 x/y/z 三个方向的旋转量左上角面板实时反馈当前数值单击鼠标左键清空屏幕重新作画。下方为示例的实际运行截图从示例到实战几个可扩展方向换成曲线顶点把ofVertex换成ofCurveVertex轨迹会从折线变成平滑的 Catmull-Rom 曲线画感更圆润引入 z 轴深度示例默认 z 分量为 0若在mouseDragged中根据鼠标速度或时间给pts[nPts].z赋值即可画出真正的 3D 轨迹保存与回放将pts数组序列化到文件即可实现笔迹的保存、回放或导出理解变换顺序平移—旋转—平移是绕任意点做旋转变换的通用模板在 ofMesh.inl 等引擎内部代码中同样可以见到glm::rotate对法线、顶点做旋转运算的用法本示例正是这套数学在实际绘图中的最小可运行演示。小结vectorMathExample用不到 200 行代码串起了 openFrameworks 中三个最常用的基础能力glm::vec3矢量数据、ofBeginShape()/ofVertex()/ofEndShape()自定义形状绘制以及绕任意点旋转的变换套路。它是理解后续particlesExample、3DPrimitivesExample等 math/3d 示例的良好起点——矢量不再只是数学课本上的概念而是你手中笔迹的每一个点。赞分享图形学音视频【免费下载链接】openFrameworksopenFrameworks is a community-developed cross platform toolkit for creative coding in C.项目地址https://gitcode.com/gh_mirrors/op/openFrameworks点击查看免费下载相关推荐openFrameworks iOS 字体渲染实战用 ofTrueTypeFont 与 ofPath 实现位图/矢量字形绘制openFrameworks iOS 字体渲染实战用 ofTrueTypeFont 与 ofPath 实现位图/矢量字形绘制 本篇文章基于 openFrame图形学音视频openFrameworks 一维噪声实战指南用 ofSignedNoise 驱动波形、旋转与颜色openFrameworks 一维噪声实战指南用 ofSignedNoise 驱动波形、旋转与颜色 openFrameworks 一维噪声实战指南用 ofS图形学音视频FlappySwift中的自定义绘制使用SKShapeNode创建矢量图形FlappySwift中的自定义绘制使用SKShapeNode创建矢量图形 在游戏开发中视觉元素的呈现往往决定了游戏的吸引力。FlappySwift作为经典游戏开发上一篇KMS_VL_ALL_AIO3分钟完成Windows和Office永久激活的终极指南下一篇OpenSearch 贡献者工程手册仓库结构、构建、测试与提交规范的源码级解析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表