免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 5227 | 回复: 2
打印 上一主题 下一主题

[Perl+OpenGL]模仿贝塞尔曲线屏保效果 [复制链接]

论坛徽章:
12
子鼠
日期:2014-10-11 16:46:482016科比退役纪念章
日期:2018-03-16 10:24:0515-16赛季CBA联赛之山东
日期:2017-11-10 14:32:142016科比退役纪念章
日期:2017-09-02 15:42:4715-16赛季CBA联赛之佛山
日期:2017-08-28 17:11:5515-16赛季CBA联赛之浙江
日期:2017-08-24 16:55:1715-16赛季CBA联赛之青岛
日期:2017-08-17 19:55:2415-16赛季CBA联赛之天津
日期:2017-06-29 10:34:4315-16赛季CBA联赛之四川
日期:2017-05-16 16:38:55黑曼巴
日期:2016-07-19 15:03:112015亚冠之萨济拖拉机
日期:2015-05-22 11:38:5315-16赛季CBA联赛之北京
日期:2019-08-13 17:30:53
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2015-01-03 14:53 |只看该作者 |倒序浏览
本帖最后由 523066680 于 2015-01-03 15:05 编辑

首先当然是要安装OpenGL模块。
旧版本的OpenGL自带Bezier求值器,但是并不返回坐标值,而是求值并帮你进行了顶点绘制操作。
为了能够更自由地操纵顶点数据,还是到wikipedia挖了一段函数:
zh.wikipedia.org/wiki/貝茲曲線 ,将 PointOnCubicBezier函数 转成Perl语言的格式

然后用50x50x3的结构数组对顶点进行存储,迭代替换,效果就做出来啦,应该还有很大优化空间


图片都超过1MB,其他的发到网络相册里了 paktc.lofter.com/post/45586_4f19e97
  1. =info
  2.     Code By: vicyang/5230
  3.     E-mail : paktcmail@gmail.com
  4.     DATE   : 2015-01-02
  5. =cut

  6. use v5.16;
  7. use IO::Handle;
  8. use OpenGL qw/ :all /;
  9. use OpenGL::Config;
  10. use Time::HiRes 'sleep';

  11. STDOUT->autoflush(1);

  12. our $WinID;
  13. &Main();

  14. sub delta {
  15.     my ($pta, $ptb) = @_;
  16.     my $dtx = ($ptb->[0] - $pta->[0]);
  17.     my $dty = ($ptb->[1] - $pta->[1]);
  18.     my $delta = sqrt ($dtx ** 2 + $dty ** 2);
  19.     return ($delta, $dtx, $dty);
  20. }

  21. sub PointOnCubicBezier {
  22.     my ($cp0, $cp1, $cp2, $cp3, $t) = @_;

  23.     my ($cx, $bx, $ax, $cy, $by, $ay);
  24.     my ($tSquared, $tCubed, $result);

  25.     $cx = 3.0 * ($cp1->[0] - $cp0->[0]);
  26.     $bx = 3.0 * ($cp2->[0] - $cp1->[0]) - $cx;
  27.     $ax = $cp3->[0] - $cp0->[0] - $cx - $bx;

  28.     $cy = 3.0 * ($cp1->[1] - $cp0->[1]);
  29.     $by = 3.0 * ($cp2->[1] - $cp1->[1]) - $cy;
  30.     $ay = $cp3->[1] - $cp0->[1] - $cy - $by;

  31.     $tSquared = $t **2;
  32.     $tCubed = $t **3;

  33.     $result->[0] = (
  34.             ($ax * $tCubed) +
  35.             ($bx * $tSquared) +
  36.             ($cx * $t) +
  37.             $cp0->[0]
  38.         );
  39.     $result->[1] = (
  40.             ($ay * $tCubed) +
  41.             ($by * $tSquared) +
  42.             ($cy * $t) +
  43.             $cp0->[1]
  44.         );

  45.     return $result;
  46. }

  47. sub getRevPoint {
  48.     my ($A, $O, $B) = (shift, shift, undef);

  49.     $B->[0] = $O->[0] + ($O->[0] - $A->[0]);
  50.     $B->[1] = $O->[1] + ($O->[1] - $A->[1]);

  51.     return $B;
  52. }

  53. sub display {
  54.     state $count = 0;
  55.     state $loops = 0;

  56.     my ($i, $j);
  57.     my $coord;
  58.    
  59.     my ($dt, $dtx, $dty);

  60.     state $n_cpts = 4;            #四个控制点
  61.     state $cpts_path_parts = 50;  
  62.     state $bezier_parts = 50;     #每条贝塞尔曲线分50部分
  63.     state $n_bezier = 50;         #贝塞尔曲线的堆叠数量
  64.     state $curve = [];            #每个cpt的曲线路径存储
  65.     state $pti = 0;               #pti数组记录4个cpt的其自身的cpt'坐标
  66.     state $pt = [
  67.         [0.0, 0.0],
  68.         [0.0, 0.0],
  69.         [0.0, 0.0],
  70.         [0.0, 0.0],
  71.     ];

  72.     state $ptarr = [];

  73.     if (($loops == 0) and ($count == 0)) {
  74.         for $i (0 .. $n_bezier-1) {
  75.             for $j (0 .. $bezier_parts) {
  76.                 $ptarr->[$i][$j] = [1000.0, -1000.0];
  77.             }

  78.             $curve->[$i] = [
  79.                 [rand(200)-100.0, rand(200)-100.0],
  80.                 [rand(200)-100.0, rand(200)-100.0],
  81.                 [rand(200)-100.0, rand(200)-100.0],
  82.                 [rand(200)-100.0, rand(200)-100.0]
  83.             ]
  84.         }
  85.     }
  86.    
  87.     #处理四个控制点的演变
  88. RECOUNT:
  89.     if ( $pti <= $cpts_path_parts ) {
  90.         for $i (0 .. $n_cpts-1) {
  91.             $coord = &PointOnCubicBezier(
  92.                     @{$curve->[$i]}[0..3],
  93.                     $pti/$cpts_path_parts
  94.             );
  95.             $pt->[$i] = $coord;  #第 $i+1 个 cpt 的坐标
  96.         }
  97.         $pti++;
  98.     } else {
  99.         #控制点超过50次的时候,创建新的随机控制点,从头开始
  100.         #起点是上一次的第50个点,同时也是新曲线的第0点
  101.         #为了避免点重合,新的曲线点下标从1开始,而不是0开始
  102.         for $i (0 .. $n_cpts-1) {
  103.             $curve->[$i] = [
  104.                 $pt->[$i],
  105.                 getRevPoint($curve->[$i][2], $curve->[$i][3]),
  106.                 #Control Point 3 is A, Point 4 is O, Find Point B
  107.                 [rand(200)-100.0, rand(200)-100.0],
  108.                 [rand(200)-100.0, rand(200)-100.0]
  109.             ];
  110.         }
  111.         $pti = 1;
  112.         goto RECOUNT;
  113.     }


  114.     glClear(GL_COLOR_BUFFER_BIT);
  115.     glBlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA);

  116.     glPushMatrix();
  117.         for $i (0 .. $bezier_parts ) {
  118.             $coord = &PointOnCubicBezier(
  119.                 @{$pt}[0, 1, 2, 3],
  120.                 $i/$bezier_parts
  121.             );
  122.             $ptarr->[$count][$i] = $coord;
  123.         }

  124.         glBegin(GL_POINTS);
  125.         

  126.         for $i (0 .. $n_bezier-1) {
  127.             glColor4f(0.4, 0.6, 0.8, 0.5);
  128.             for $j (0.0 .. $bezier_parts) {
  129.                 glVertex3f($ptarr->[$i][$j][0], $ptarr->[$i][$j][1], 0.0);
  130.             }
  131.         }
  132.         glEnd();

  133.     glPopMatrix();
  134.     glutSwapBuffers();

  135.     if ($count < ($n_bezier-1)) {
  136.         $count++;
  137.     } else {
  138.         $count = 0;
  139.         $loops++;
  140.     }

  141. }

  142. sub init {
  143.     glClearColor(0.0, 0.0, 0.0, 1.0);
  144.     glPointSize(5.0);
  145.     glLineWidth(10.0);
  146.     glEnable(GL_BLEND);
  147.     glEnable(GL_POINT_SMOOTH);
  148.     glEnable(GL_LINE_SMOOTH);
  149. }

  150. sub idle {
  151.     sleep 0.05;
  152.     glutPostRedisplay();
  153. }

  154. sub Reshape {
  155.     glViewport(0.0,0.0,500.0,500.0);
  156.     glMatrixMode(GL_PROJECTION);
  157.     glLoadIdentity();
  158.     glOrtho(-100.0,100.0,-100.0,100.0,0.0,200.0);
  159.     glMatrixMode(GL_MODELVIEW);
  160.     glLoadIdentity();
  161.     gluLookAt(0.0,0.0,100.0,0.0,0.0,0.0, 0.0,1.0,100.0);
  162. }

  163. sub hitkey {
  164.     my $key = shift;
  165.     if (lc(chr($key)) eq 'q') {
  166.         glutDestroyWindow($WinID);
  167.     } elsif ($key == 27) {
  168.         glutDestroyWindow($WinID);
  169.     }
  170. }

  171. sub Main {
  172.     glutInit();
  173.     glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE );#| GLUT_MULTISAMPLE);
  174.     glutInitWindowSize(500, 500);
  175.     glutInitWindowPosition(1,1);
  176.     our $WinID = glutCreateWindow("Curve_Vic");
  177.     &init();
  178.     glutDisplayFunc(\&display);
  179.     glutReshapeFunc(\&Reshape);
  180.     glutKeyboardFunc(\&hitkey);
  181.     glutIdleFunc(\&idle);
  182.     glutMainLoop();
  183. }
复制代码

论坛徽章:
8
技术图书徽章
日期:2013-08-22 11:21:28未羊
日期:2015-01-19 22:22:25巳蛇
日期:2014-08-11 16:53:08子鼠
日期:2014-05-29 09:04:44摩羯座
日期:2014-04-11 14:15:07丑牛
日期:2014-01-24 12:41:28金牛座
日期:2013-11-21 17:38:28射手座
日期:2015-01-21 08:50:32
2 [报告]
发表于 2015-01-04 13:17 |只看该作者
(๑ŐдŐb哇~点赞

论坛徽章:
0
3 [报告]
发表于 2015-01-05 11:50 |只看该作者
好炫酷,牛!
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP