Skip to content

Instantly share code, notes, and snippets.

@vividsnow
Last active December 11, 2015 10:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vividsnow/ae6b4eb17015f8749173 to your computer and use it in GitHub Desktop.
Save vividsnow/ae6b4eb17015f8749173 to your computer and use it in GitHub Desktop.
void main (void) {
float d = distance(vec2(0.5), gl_PointCoord);
if (d >= 0.5) { discard; }
gl_FragColor = vec4(gl_Color.rgb, max(2 * (0.5 - d), 0) * gl_Color.a);
}
package Vz::Node::3d::Rotor;
use v5.16;
use Moo;
extends 'Vz::Node';
use OpenGL ':all';
use Math::SegmentedEnvelope 'env';
use PDL;
use PDL::Constants qw(PI E I);
use PDL::Stats::TS;
use PDL::Image2D;
use AnyEvent;
use List::Util 'shuffle';
use Time::HiRes qw'gettimeofday tv_interval';
use Memoize;
use namespace::autoclean;
has qw(rotate is rw default), sub { pdl 0,0,0 };
has qw(scale is rw default), sub { [1,1,1] };
has qw(trail is rw default), sub { [1,1] };
has qw(buf is rw lazy 1 default), sub {
my $self = shift;
(my $ar = OpenGL::Array->new($self->num_of_points * 16, GL_FLOAT))->bind(my $id = glGenBuffersARB_p(1)); # x y z r g b a s x 2
glBufferDataARB_p(GL_ARRAY_BUFFER_ARB, $ar, GL_DYNAMIC_DRAW_ARB);
$id;
};
has qw(point_size is rw default), sub { 40 };
has qw(attenuation is rw default), sub { 0.73 };
has qw(last_shape is rw default), sub { 0 };
has qw(transit_smooth is rw default), sub { 1 };
has qw(num_of_points is rw default), sub { 236 };
has qw(shader is rw lazy 1 default), sub { shift->world->parent->tools->shader->make(qw'rotor trail') };
has on_add => is => rw => default => sub { [ sub {
shift->create_shape;
} ] };
has on_display => is => rw => default => sub { [ sub {
my $self = shift;
my $shader = $self->shader;
state $started = AE::now;
state $previous = 0;
my $now = AE::now - $started;
my $elapsed = $now - $previous;
$previous = $now;
glPushAttrib(GL_ENABLE_BIT|GL_POINT_BIT);
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
glEnable(GL_POINT_SPRITE);
glEnable(GL_COLOR_MATERIAL);
glPushMatrix();
glTranslatef(0,0,-1);
glScaled(@{$self->scale});
$shader->enable;
glBindBufferARB(GL_ARRAY_BUFFER_ARB, $self->buf);
map glEnableClientState($_), GL_VERTEX_ARRAY, GL_COLOR_ARRAY;
glVertexPointer_c(3, GL_FLOAT,(my $stride = 4*8), 0); # 4 float size, 8 xyzsrgba
glEnableVertexAttribArrayARB(my $size_idx = $shader->attr('cur_size'));
glVertexAttribPointerARB_c($size_idx, 1, GL_FLOAT, GL_FALSE, $stride, (my $size_offset = 3*4));
glColorPointer_c(4, GL_FLOAT, $stride, (my $color_offset = 4*4));
glEnableVertexAttribArrayARB(my $next_pos_idx = $shader->attr('next_pos'));
glVertexAttribPointerARB_c($next_pos_idx, 3, GL_FLOAT, GL_FALSE, $stride, (my $next_shape = $self->num_of_points * $stride));
glEnableVertexAttribArrayARB(my $next_size_idx = $shader->attr('next_size'));
glVertexAttribPointerARB_c($next_size_idx, 1, GL_FLOAT, GL_FALSE, $stride, $next_shape + $size_offset);
glEnableVertexAttribArrayARB(my $next_clr_idx = $shader->attr('next_clr'));
glVertexAttribPointerARB_c($next_clr_idx, 4, GL_FLOAT, GL_FALSE, $stride, $next_shape + $color_offset);
glPointParameterfvARB_p(GL_POINT_DISTANCE_ATTENUATION, 0, 0, $self->attenuation);
map {
glPushMatrix();
glPointSize($self->point_size / sqrt sqrt $_);
glTranslatef(0,0,-0.5);
state $rot;
$rot = $self->rotate * $now % 1 * 360; # $fix + $now for smoothing
map glRotatef($rot->at($_), (0)x$_, 1, (0)x(2-$_)), 0..2;
glTranslatef(-0.5,-0.5,-0.5);
$shader->vec(f => cf => (1)x3, 1 / sqrt $_);
$shader->vec(f => morph => $self->morph_pos($now));
glDrawArrays(GL_POINTS, 0, $self->num_of_points);
glPopMatrix();
$now -= ($_ * $elapsed / $self->trail->[0]);
} 1..$self->trail->[1];
map glDisableVertexAttribArrayARB($_), $size_idx, $next_pos_idx, $next_size_idx, $next_clr_idx;
map glDisableClientState($_), GL_VERTEX_ARRAY, GL_COLOR_ARRAY;
$shader->disable;
glPopMatrix();
glPopAttrib();
} ] };
sub create_shape {
my ($self, $ind) = @_;
return do {
$self->create_rotate;
map $self->create_shape($_), 0..1;
} unless defined $ind;
my $t0 = [gettimeofday];
my $complex = int(rand(2));
my $eq_spaced = int(rand(2));
my $points = $self->num_of_points; #int rand(300) + 100;
# my $vert = pdl(float, map { [ env(is_morph => 1)->table($points, $complex ? int(rand(3)+1) : 1) ] } 0..7)->transpose->flat;
my $vert = pdl(float, map { [ env(is_morph => 1)->table($points, $complex ? int(rand(3)+1) : 1) ] } 0..7);
equally_spaced_curve($vert->slice(':,0:2')) if $eq_spaced;
$vert = $vert->transpose->flat;
(my $data = OpenGL::Array->new_scalar(GL_FLOAT, $vert->get_dataref, $vert->dim(0)*4))->bind($self->buf);
#glBufferSubDataARB_c(GL_ARRAY_BUFFER_ARB, $ind*$vert->dim(0)*4, $vert->dim(0)*4, $data->ptr);
glBufferSubDataARB_p(GL_ARRAY_BUFFER_ARB, $ind*$vert->dim(0), $data);
# seems that *_p knows of type of $data, so offset should be in type elements, not bytes
say 'tooks to create ', $ind, ' ', tv_interval($t0);
}
sub create_rotate {
my $self = shift;
$self->set(
rotate => pdl(map { int(rand(2)) ? -1 : 1 } 1..3) * pdl(shuffle map { (4+rand(1.2))/2**$_ } 1, 4, 6),
scale => [ +(ones(3) + pdl(map { int(rand(2)) ? -1 : 1 } 1..3) * pdl(shuffle map 1/2**$_, (1..3)))->list ],
trail => [ 1 + int rand 9, 3 + int rand 7 ]
);
}
sub transit_rotate {
my ($self) = @_;
my $old_rot = $self->rotate;
my $df = pdl(map { int(rand(2)) ? -1 : 1 } 1..3) * pdl(shuffle map { (4+rand(1.2))/2**$_ } 1, 4, 6) - $old_rot;
my $k = 0;
$self->timer->add( rotate_transit => sub {
$k += $self->timer->rate;
$self->rotate($old_rot + $df*$k);
}, 1 );
}
sub transit {
my ($self) = @_;
$self->timer->add( transit_begin => sub {
$self->transit_smooth(abs( $self->transit_smooth - 1/25 ));
}, 1, 0, sub {
$self->transit_smooth(0);
$self->create_shape(!$self->last_shape+0);
$self->timer->add( transit_end => sub {
$self->transit_smooth($self->transit_smooth + 1/25);
}, 1, 0, sub {
$self->transit_smooth(1);
$self->last_shape(!$self->last_shape+0);
}, 1/24);
}, 1/25);
}
sub morph_pos {
state $evaluator = memoize sub {
(sin($_[0])*0.5+0.5) * $_[1] + $_[2] * abs(1 - $_[1]);
};
$evaluator->($_[1], $_[0]->transit_smooth, $_[0]->last_shape);
}
sub restart { shift->create_shape }
sub equally_spaced_curve {
my ($l, $points) = @_;
say 'make eq cureve';
$points //= $l->dim(0);
my $start_vals = $l->slice('(0),:')->transpose;
$l -= $start_vals;
my $len_total = (my $df = $l->diff->pow(2)->transpose->sumover->sqrt->cumusumover)->at(-1);
my $positions = (zeroes(1)->append(ones($points-1)*$len_total/$points))->cumusumover;
my $smooth = 3 + int rand 5;
$l .= conv2d +(pdl(map { interpol($positions, $df, $l->slice(':,('.$_.')')) } 0..$l->dim(1)-1) + $start_vals)/5, ones(5), { Boundary => 'Reflect' };
}
1;
#!/usr/bin/env perl
use v5.16;
use Vz;
my $vz = Vz->new;
$vz->add(camera => [ '3d_rotor' => {
init => sub {
my $self = shift;
$vz->window->bind_key(t => sub { $self->create_shape } );
$vz->window->bind_key(r => sub { $self->transit_rotate } );
$vz->window->bind_key(g => sub { $self->transit } );
$vz->window->bind_key(v => sub { $self->trail->[0]-- } );
$vz->window->bind_key(b => sub { $self->trail->[0]++ } );
$vz->window->bind_key(n => sub { $self->trail->[1]-- } );
$vz->window->bind_key(m => sub { $self->trail->[1]++ } );
}
} ]);
$vz->play;
uniform vec4 cf;
uniform float morph;
attribute vec3 next_pos;
attribute float next_size;
attribute vec4 next_clr;
attribute float cur_size;
void main(void) {
vec4 vert = mix(gl_Vertex, vec4(next_pos, gl_Vertex.w), morph);
gl_Position = gl_ModelViewProjectionMatrix * vert;
float dist = distance(gl_ModelViewMatrix * vert, vec3(0,0,1));
vec4 color = mix(gl_Color, next_clr, morph);
gl_FrontColor = vec4(color.rgb, 1);//color.a * cf.a / dist
gl_PointSize = (0.1 + mix(cur_size, next_size, morph)) * gl_Point.size * sqrt(1.0 / (gl_Point.distanceQuadraticAttenuation * dist * dist));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment