Board logo

标题: [原创代码] Perl绘制Bezier曲线渐变效果 [打印本页]

作者: 523066680    时间: 2015-3-19 10:41     标题: Perl绘制Bezier曲线渐变效果

环境:WinXP/Win7  Perl v5.16.3
需要图形渲染模块:OpenGL

单条Bezier的绘制函数参考 Wikipedia:貝茲曲線
  1. =info
  2.     Code By 523066680/vicyang
  3.     2015-01-02
  4. =cut
  5. use v5.16;
  6. use IO::Handle;
  7. use OpenGL qw/ :all /;
  8. use OpenGL::Config;
  9. use Time::HiRes 'sleep';
  10. STDOUT->autoflush(1);
  11. our $WinID;
  12. &Main();
  13. sub delta {
  14.     my ($pta, $ptb) = @_;
  15.     my $dtx = ($ptb->[0] - $pta->[0]);
  16.     my $dty = ($ptb->[1] - $pta->[1]);
  17.     my $delta = sqrt ($dtx ** 2 + $dty ** 2);
  18.     return ($delta, $dtx, $dty);
  19. }
  20. sub PointOnCubicBezier {
  21.     my ($cp0, $cp1, $cp2, $cp3, $t) = @_;
  22.     my ($cx, $bx, $ax, $cy, $by, $ay);
  23.     my ($tSquared, $tCubed, $result);
  24.     $cx = 3.0 * ($cp1->[0] - $cp0->[0]);
  25.     $bx = 3.0 * ($cp2->[0] - $cp1->[0]) - $cx;
  26.     $ax = $cp3->[0] - $cp0->[0] - $cx - $bx;
  27.     $cy = 3.0 * ($cp1->[1] - $cp0->[1]);
  28.     $by = 3.0 * ($cp2->[1] - $cp1->[1]) - $cy;
  29.     $ay = $cp3->[1] - $cp0->[1] - $cy - $by;
  30.     $tSquared = $t **2;
  31.     $tCubed = $t **3;
  32.     $result->[0] = (
  33.             ($ax * $tCubed) +
  34.             ($bx * $tSquared) +
  35.             ($cx * $t) +
  36.             $cp0->[0]
  37.         );
  38.     $result->[1] = (
  39.             ($ay * $tCubed) +
  40.             ($by * $tSquared) +
  41.             ($cy * $t) +
  42.             $cp0->[1]
  43.         );
  44.     return $result;
  45. }
  46. sub getRevPoint {
  47.     my ($A, $O, $B) = (shift, shift, undef);
  48.     $B->[0] = $O->[0] + ($O->[0] - $A->[0]);
  49.     $B->[1] = $O->[1] + ($O->[1] - $A->[1]);
  50.     return $B;
  51. }
  52. sub display {
  53.     state $count = 0;
  54.     state $loops = 0;
  55.     my ($i, $j);
  56.     my $coord;
  57.    
  58.     my ($dt, $dtx, $dty);
  59.     state $n_cpts = 4;            #四个控制点
  60.     state $cpts_path_parts = 50;  
  61.     state $bezier_parts = 30;     #每条贝塞尔曲线分30部分
  62.     state $n_bezier = 30;         #贝塞尔曲线的堆叠数量
  63.     state $curve = [];            #每个cpt的曲线路径存储
  64.     state $pti = 0;               #pti数组记录4个cpt的其自身的cpt'坐标
  65.     state $pt = [
  66.         [0.0, 0.0],
  67.         [0.0, 0.0],
  68.         [0.0, 0.0],
  69.         [0.0, 0.0],
  70.     ];
  71.     state $ptarr = [];
  72.     if (($loops == 0) and ($count == 0)) {
  73.         for $i (0 .. $n_bezier-1) {
  74.             for $j (0 .. $bezier_parts) {
  75.                 $ptarr->[$i][$j] = [1000.0, -1000.0];
  76.             }
  77.             $curve->[$i] = [
  78.                 [rand(200)-100.0, rand(200)-100.0],
  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.             ]
  83.         }
  84.     }
  85.    
  86.     #处理四个控制点的演变
  87. RECOUNT:
  88.     if ( $pti <= $cpts_path_parts ) {
  89.         for $i (0 .. $n_cpts-1) {
  90.             $coord = &PointOnCubicBezier(
  91.                     @{$curve->[$i]}[0..3],
  92.                     $pti/$cpts_path_parts
  93.             );
  94.             $pt->[$i] = $coord;  #第 $i+1 个 cpt 的坐标
  95.         }
  96.         $pti++;
  97.     } else {
  98.         #控制点超过50次的时候,创建新的随机控制点,从头开始
  99.         #起点是上一次的第50个点,同时也是新曲线的第0点
  100.         #为了避免点重合,新的曲线点下标从1开始,而不是0开始
  101.         for $i (0 .. $n_cpts-1) {
  102.             $curve->[$i] = [
  103.                 $pt->[$i],
  104.                 getRevPoint($curve->[$i][2], $curve->[$i][3]),
  105.                 #Control Point 3 is A, Point 4 is O, Find Point B
  106.                 [rand(200)-100.0, rand(200)-100.0],
  107.                 [rand(200)-100.0, rand(200)-100.0]
  108.             ];
  109.         }
  110.         $pti = 1;
  111.         goto RECOUNT;
  112.     }
  113.     glClear(GL_COLOR_BUFFER_BIT);
  114.     glBlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA);
  115.     glPushMatrix();
  116.         for $i (0 .. $bezier_parts ) {
  117.             $coord = &PointOnCubicBezier(
  118.                 @{$pt}[0, 1, 2, 3],
  119.                 $i/$bezier_parts
  120.             );
  121.             $ptarr->[$count][$i] = $coord;
  122.         }
  123.         glBegin(GL_POINTS);
  124.         
  125.         for $i (0 .. $n_bezier-1) {
  126.             glColor4f(0.4, 0.6, 0.8, 0.5);
  127.             for $j (0.0 .. $bezier_parts) {
  128.                 glVertex3f($ptarr->[$i][$j][0], $ptarr->[$i][$j][1], 0.0);
  129.             }
  130.         }
  131.         glEnd();
  132.     glPopMatrix();
  133.     glutSwapBuffers();
  134.     if ($count < ($n_bezier-1)) {
  135.         $count++;
  136.     } else {
  137.         $count = 0;
  138.         $loops++;
  139.     }
  140. }
  141. sub init {
  142.     glClearColor(0.0, 0.0, 0.0, 1.0);
  143.     glPointSize(6.0);
  144.     glLineWidth(10.0);
  145.     glEnable(GL_BLEND);
  146.     glEnable(GL_POINT_SMOOTH);
  147.     glEnable(GL_LINE_SMOOTH);
  148. }
  149. sub idle {
  150.     sleep 0.05;
  151.     glutPostRedisplay();
  152. }
  153. sub Reshape {
  154.     glViewport(0.0,0.0,500.0,500.0);
  155.     glMatrixMode(GL_PROJECTION);
  156.     glLoadIdentity();
  157.     glOrtho(-100.0,100.0,-100.0,100.0,0.0,200.0);
  158.     glMatrixMode(GL_MODELVIEW);
  159.     glLoadIdentity();
  160.     gluLookAt(0.0,0.0,100.0,0.0,0.0,0.0, 0.0,1.0,100.0);
  161. }
  162. sub hitkey {
  163.     my $key = shift;
  164.     if (lc(chr($key)) eq 'q') {
  165.         glutDestroyWindow($WinID);
  166.     } elsif ($key == 27) {
  167.         glutDestroyWindow($WinID);
  168.     }
  169. }
  170. sub Main {
  171.     glutInit();
  172.     glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE );#| GLUT_MULTISAMPLE);
  173.     glutInitWindowSize(500, 500);
  174.     glutInitWindowPosition(1,1);
  175.     our $WinID = glutCreateWindow("Curve_Vic");
  176.     &init();
  177.     glutDisplayFunc(\&display);
  178.     glutReshapeFunc(\&Reshape);
  179.     glutKeyboardFunc(\&hitkey);
  180.     glutIdleFunc(\&idle);
  181.     glutMainLoop();
  182. }
复制代码

作者: CrLf    时间: 2015-3-19 12:28

膜拜
作者: 523066680    时间: 2015-3-19 12:37

本帖最后由 523066680 于 2015-3-19 12:38 编辑

回复 2# CrLf


      在某个文艺社区溜达的时候得知有一种可以做UI动画的软件叫做After Effect  (一般配置还跑不起-_-)

效果请看:
http://onedesigner.lofter.com/post/28cbcd_4118d8a

http://onedesigner.lofter.com/post/28cbcd_42b6492
作者: CrLf    时间: 2015-3-19 13:00

回复 3# 523066680


    妈的,仔细一看是 ae,ae我也会好吗
作者: 523066680    时间: 2015-3-19 14:25

回复 4# CrLf


    好强……  AE做这个好像比写代码容易啊。可惜我电脑跑不动……
作者: CrLf    时间: 2015-3-19 14:36

回复 5# 523066680


    要是 ae 更麻烦,adobe 公司可以去死了
作者: happy886rr    时间: 2016-5-12 19:36

梦幻般的感觉,看来我应该去学perl.平滑度极佳,完全是活的,希望能看到彩色水母.
作者: codegay    时间: 2016-5-12 19:40

回复 7# happy886rr


   
进我安利的坑,别跑
作者: codegay    时间: 2016-5-12 20:02

本帖最后由 codegay 于 2016-5-12 20:17 编辑

Processing 是一门主要做多媒体交互的。有很多很酷作品。
网上的作品展示有分形动图,
数据可视化,

多媒体交互 http://i.youku.com/u/UMzY0MDQyODIw

这里有一些作品 http://ravenkwok.com/

像这种的也有http://www.tudou.com/programs/view/V4QVzwcPe3Q/
作者: happy886rr    时间: 2016-5-12 20:19

回复 8# codegay
我都只学个皮毛,要精通没个一年很难.if exist善于用脚本语言展现动态美,蕴含许多巧妙设计.不借助软件工具,单靠脚本去实现动画.
作者: codegay    时间: 2016-5-12 20:31

回复 10# happy886rr


    脚本和语言也只是工具啊。
作者: 523066680    时间: 2016-9-26 15:34

本帖最后由 523066680 于 2016-9-26 17:28 编辑

回复 9# codegay

     前段时间接触过Processing,好像是依赖JAVA环境的,光是开个IDE就卡得出翔,连运行实例的心情都没了。
果断放弃。

回复 7# happy886rr
Perl 还是适合文本操作,恩。除非对Perl的代码风格有好感,否则不建议用Perl做太多别的事情。

Ruby好像不错,但是一直没去深入。不过真正要做点应用的话,我觉得还是应该上C#或C++




欢迎光临 批处理之家 (http://www.bathome.net/) Powered by Discuz! 7.2