[OpenGL]贝塞尔曲线渐变效果

There's more than one way to do it!

[OpenGL]贝塞尔曲线渐变效果

帖子523066680 » 2015-12-11 20:44

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

单条Bezier的绘制函数参考 Wikipedia:貝茲曲線

效果:
图片

Syntax: [ Download ] [ Hide ]
=info
    Code By 523066680/vicyang
    2015-01-02
=cut

use v5.16;
use IO::Handle;
use OpenGL qw/ :all /;
use OpenGL::Config;
use Time::HiRes 'sleep';

STDOUT->autoflush(1);

our $WinID;
&Main();

sub delta {
    my ($pta, $ptb) = @_;
    my $dtx = ($ptb->[0] - $pta->[0]);
    my $dty = ($ptb->[1] - $pta->[1]);
    my $delta = sqrt ($dtx ** 2 + $dty ** 2);
    return ($delta, $dtx, $dty);
}

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

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

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

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

    $tSquared = $t **2;
    $tCubed = $t **3;

    $result->[0] = (
            ($ax * $tCubed) +
            ($bx * $tSquared) +
            ($cx * $t) +
            $cp0->[0]
        );
    $result->[1] = (
            ($ay * $tCubed) +
            ($by * $tSquared) +
            ($cy * $t) +
            $cp0->[1]
        );

    return $result;
}

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

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

    return $B;
}

sub display {
    state $count = 0;
    state $loops = 0;

    my ($i, $j);
    my $coord;
   
    my ($dt, $dtx, $dty);

    state $n_cpts = 4;            #四个控制点
    state $cpts_path_parts = 50;  
    state $bezier_parts = 30;     #每条贝塞尔曲线分30部分
    state $n_bezier = 30;         #贝塞尔曲线的堆叠数量
    state $curve = [];            #每个cpt的曲线路径存储
    state $pti = 0;               #pti数组记录4个cpt的其自身的cpt'坐标
    state $pt = [
        [0.0, 0.0],
        [0.0, 0.0],
        [0.0, 0.0],
        [0.0, 0.0],
    ];

    state $ptarr = [];

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

            $curve->[$i] = [
                [rand(200)-100.0, rand(200)-100.0],
                [rand(200)-100.0, rand(200)-100.0],
                [rand(200)-100.0, rand(200)-100.0],
                [rand(200)-100.0, rand(200)-100.0]
            ]
        }
    }
   
    #处理四个控制点的演变
RECOUNT:
    if ( $pti <= $cpts_path_parts ) {
        for $i (0 .. $n_cpts-1) {
            $coord = &PointOnCubicBezier(
                    @{$curve->[$i]}[0..3],
                    $pti/$cpts_path_parts
            );
            $pt->[$i] = $coord;  #第 $i+1 个 cpt 的坐标
        }
        $pti++;
    } else {
        #控制点超过50次的时候,创建新的随机控制点,从头开始
        #起点是上一次的第50个点,同时也是新曲线的第0点
        #为了避免点重合,新的曲线点下标从1开始,而不是0开始
        for $i (0 .. $n_cpts-1) {
            $curve->[$i] = [
                $pt->[$i],
                getRevPoint($curve->[$i][2], $curve->[$i][3]),
                #Control Point 3 is A, Point 4 is O, Find Point B
                [rand(200)-100.0, rand(200)-100.0],
                [rand(200)-100.0, rand(200)-100.0]
            ];
        }
        $pti = 1;
        goto RECOUNT;
    }


    glClear(GL_COLOR_BUFFER_BIT);
    glBlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA);

    glPushMatrix();
        for $i (0 .. $bezier_parts ) {
            $coord = &PointOnCubicBezier(
                @{$pt}[0, 1, 2, 3],
                $i/$bezier_parts
            );
            $ptarr->[$count][$i] = $coord;
        }

        glBegin(GL_POINTS);
       

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

    glPopMatrix();
    glutSwapBuffers();

    if ($count < ($n_bezier-1)) {
        $count++;
    } else {
        $count = 0;
        $loops++;
    }

}

sub init {
    glClearColor(0.0, 0.0, 0.0, 1.0);
    glPointSize(6.0);
    glLineWidth(10.0);
    glEnable(GL_BLEND);
    glEnable(GL_POINT_SMOOTH);
    glEnable(GL_LINE_SMOOTH);
}

sub idle {
    sleep 0.05;
    glutPostRedisplay();
}

sub Reshape {
    glViewport(0.0,0.0,500.0,500.0);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-100.0,100.0,-100.0,100.0,0.0,200.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(0.0,0.0,100.0,0.0,0.0,0.0, 0.0,1.0,100.0);
}

sub hitkey {
    my $key = shift;
    if (lc(chr($key)) eq 'q') {
        glutDestroyWindow($WinID);
    } elsif ($key == 27) {
        glutDestroyWindow($WinID);
    }
}

sub Main {
    glutInit();
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE );#| GLUT_MULTISAMPLE);
    glutInitWindowSize(500, 500);
    glutInitWindowPosition(1,1);
    our $WinID = glutCreateWindow("Curve_Vic");
    &init();
    glutDisplayFunc(\&display);
    glutReshapeFunc(\&Reshape);
    glutKeyboardFunc(\&hitkey);
    glutIdleFunc(\&idle);
    glutMainLoop();
}
 
论坛已转移 Code-By.Org 群号 322023604
头像
523066680
版主
 
帖子: 1680
注册: 2012-03-06 15:08

回到 Perl

在线用户

正在浏览此版面的用户:没有注册用户 和 1 位游客

cron
Not able to open ./cache/data_global.php