![](/i/fill.gif) |
![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
stbenge schrieb:
> Good job! I think I'll stick to C programming for this effect though.
> It's easy enough to produce a barrier and generator mask using POV, and
> then take it into C to run the sim :/
I mainly did it because the C(/++) program I had written earlier only
produced ASCII art output, and it did quite well for starters, but I got
tired of its limitations, and was too lazy to integrate support for
proper image reading and writing ;-)
And, of course, misusing POV-Ray in this manner was an interesting
challenge to do ;-)
Next on the agenda: Game of life. Should be a piece of cake if done
properly: Read in last frame, apply a color map according to birth/death
rules, overlay with 8 tuned-down displaced copies to add birth/death
hints for the next step - render.
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
stbenge schrieb:
>> We have no persistent variables, but using images would work.
>
> I guess a person could #write to a file and generate persistent
> variables that way...
You positively don't want to do that with a ripple tank sim :P
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
clipka <ano### [at] anonymous org> wrote:=
> I guess the O(n^3) applies not to an increased "tank" size, but an
> increased resolution (which then also requires an increased resolution
> of time I guess), right?
Exactly. It's the CFL (Courant-Friedrichs-Lewy) condition, and it basically
just says that information can't travel more than one grid cell per step. This
means that if you double the resolution, you also have to cut the time step in
half to preserve stability. So if you double the resolution, you have a factor
of four, and halving the time step makes 8.
> - So far I've used a more naive approach than what you propose,
> explicitly keeping track of both pressure and velocity (2 dimensions)
> separately (yet side-by-side in the same frame - hence the 3:1 aspect
> ratio), not realizing that the velocity can be inferred from the
> difference between previous frames (then again, can it? after all, the
> difference is an overlay of velocity influences in two dimensions...
> except of course if you process only a single dimension per step). This
> of course uses some weird hacks to properly superimpose the various
> dimensions.
Sorry for all the math. I just popped my head in and saw something I couldn't
resist responding to.
Mathematically, you can rewrite the wave equation as two first order PDE's:
d^2p/dt^2 = d^2p/dx^2 + d^2p/dy^2 = del^2 p
becomes
dp/dt = div( v )
dv/dt = grad( p )
This is equivalent since differentiating the first, dp/dt, gives
d^2p/dt^2 = d/dt div(v) = div( dv/dt ) = div( grad(p) ) = del^2 p
Then, as you've done, you just store three quantities (i.e. pressure and 2 x
velocity) and compute them separately. They're mathematically equivalent, but
computationally different. For my approach, you need two previous frames but
only one quantity. For your approach you need one previous frame, but three
quantities.
> Something along these lines, yes. Except that I'm not that deep into
> "official" math to know what a "laplacian" is
Sorry for the lingo; it's just the sum of second derivatives (curvature) in all
the different dimensions. If the overall curvature is downward, it accelerates
downward, and vice versa.
- Ricky
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
clipka <ano### [at] anonymous org> wrote:
> As an interesting side note, although performing bulk mathematical
> simulation, the SDL script doesn't use a single function (except for
> auxiliary purposes), not a single array, no file #write or #read, and
> only a single control statement (an #if, for special treatment of the
> very first frame). Virtually all it does is render frame after frame of
> the animation.
Sometimes you have to do things the fun way. That got me thinking. It's not
POV-Ray, but here's what I came up with. It should compile on any kind of x11
system. It's about as short as I could get it with a gui and an interesting
setup. Not written for clarity (although it's really pretty straightforward).
;-)
- Ricky
Compile with: 'cc main.c -O3 -L/usr/X11R6/lib -lX11'
Run with: ./a.out
#include <X11/Xlib.h>
#include <math.h>
int main(){int i,j,y=200,p,v;float*a,*b,
*c,*t,f[6*y*y];Display*d=XOpenDisplay(0)
;Window w=RootWindow(d,0);GC g=XCreateGC
(d,w,0,0);w=XCreateSimpleWindow(d,w,0,0,
y*2,y,0,0,0);XMapWindow(d,w);a=f;b=f+2*y
*y;c=f+y*y*4;for(i=0;i<y*y*6;f[i++]=0){}
for(;;++*f){for(i=1;i<y*2-1;i++)for(j=1;
j<y-1;j++){if((fabs(i-y)>1)|(fabs(fabs(j
-y/2)-y/10)<8)){p=i*y+j;p[a]=(b[p-1]+b[p
+1]+b[p-y]+b[p+y])/2-p[c];v=fmin(fmax(a[
p]*500+127,0),255);XSetForeground(d,g,v|
v<<8|v<<16|v<<24);XDrawPoint(d,w,g,i,j);
}}a[y*(1+y)/2]=sin(*f*.4);t=c,c=b,b=a,a=
t;}return 0;}
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
clipka wrote:
> I mainly did it because the C(/++) program I had written earlier only
> produced ASCII art output, and it did quite well for starters, but I got
> tired of its limitations, and was too lazy to integrate support for
> proper image reading and writing ;-)
>
> And, of course, misusing POV-Ray in this manner was an interesting
> challenge to do ;-)
I'm all for misusing programs and languages in this way. Heck, I'd go as
far as to say that the more unique ways you can find to accomplish a
singular goal, the better! "Unique ways" being the key of course ;)
> Next on the agenda: Game of life. Should be a piece of cake if done
> properly: Read in last frame, apply a color map according to birth/death
> rules overlay with 8 tuned-down displaced copies to add birth/death
> hints for the next step - render.
Ah, with the #if statement right near the apex of that calculation?
And with an average pattern instead of a function? Any way, I'd like to
see it :)
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
stbenge schrieb:
> I'm all for misusing programs and languages in this way. Heck, I'd go as
> far as to say that the more unique ways you can find to accomplish a
> singular goal, the better! "Unique ways" being the key of course ;)
Yeah, I'm in for such stuff, too.
>> Next on the agenda: Game of life. Should be a piece of cake if done
>> properly: Read in last frame, apply a color map according to
>> birth/death rules overlay with 8 tuned-down displaced copies to add
>> birth/death
>> hints for the next step - render.
>
> Ah, with the #if statement right near the apex of that calculation? And
> with an average pattern instead of a function? Any way, I'd like to see
> it :)
What #if statement? The code won't need any #if :-) (the color map will
serve as a kind of #switch statement).
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
clipka wrote:
> stbenge schrieb:
>> Ah, with the #if statement right near the apex of that calculation?
>> And with an average pattern instead of a function? Any way, I'd like
>> to see it :)
>
> What #if statement? The code won't need any #if :-) (the color map will
> serve as a kind of #switch statement).
Oh, I guess I was surmising based on your previous statements...
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
>> Good job! I think I'll stick to C programming for this effect though.
>> It's easy enough to produce a barrier and generator mask using POV, and
>> then take it into C to run the sim :/
>
> I mainly did it because the C(/++) program I had written earlier only
> produced ASCII art output, and it did quite well for starters, but I got
> tired of its limitations, and was too lazy to integrate support for proper
> image reading and writing ;-)
>
> And, of course, misusing POV-Ray in this manner was an interesting
> challenge to do ;-)
>
> Next on the agenda: Game of life. Should be a piece of cake if done
> properly: Read in last frame, apply a color map according to birth/death
> rules, overlay with 8 tuned-down displaced copies to add birth/death hints
> for the next step - render.
What you are doing here is actually very similar to how you write such
things for the GPU. I wrote a wave simulator for the GPU a while back and
it works almost identically, never thought of the GoL on a GPU, should be
easy to implement.
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
clipka wrote:
> ...., and was too lazy to integrate support for
> proper image reading and writing ;-)
I'm sure you already know this but ascii PPM images are the way forward
here - a nice easy human readable/writable HDRI image format.
Obviously I admire your abuse of PovRay.
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
scott schrieb:
> never thought of the GoL on a GPU, should be easy to implement.
I bet. If it can be done in POV-Ray with textures only...
Here's the full POV-Ray SDL code for a GoL sim starting with a random
pattern - the only non-linearity in control flow is the #if to care for
first-frame initialization.
The world is toroidal, though this can be chaned by enabling the "once"
keyword in the definition of PgNext.
As an interesting side note, the sim does /not/ store the end result of
each generation, but interim results: The status of the cell itself,
combined with a count of the surrounding live cells. This allows easy
use of a color_map for the conditionals.
(The code could be made shorter by using macros, but I reckon this would
be counter-productive for parsing speed.)
--------------------------------------
// +W100 +H100 +KFI1 +KFF9999 +FE
#version 3.6;
global_settings {
assumed_gamma 1.0
ambient_light 1.0
max_trace_level 15
}
camera {
orthographic
location <0,0,100>
look_at <0,0,0>
right -1*x
up 1*y
}
default {
finish { ambient 1.0 diffuse 0.0 }
}
// ----------------------------------------
#local FrameDigits = int(log(final_frame)) + 1;
#local NumLayers = 9;
#local Delta = 1/max(image_width,image_height);
#local NeighborFactor = 0.05;
#local CellFactor = 0.50;
#local EPSILON = 1e-6;
#if (frame_number = 1)
#local PgNext = pigment { bozo color_map { [ 0.499 rgb 0 ] [ 0.501
rgb 1 ] } scale Delta }
#else
#local PgNext = pigment {
image_pattern { concat("Life", str(frame_number-1,-FrameDigits,0))
/*once*/ }
color_map {
// dead cell
[ 0*CellFactor + 2.5*NeighborFactor -EPSILON rgb 0 ]
[ 0*CellFactor + 2.5*NeighborFactor +EPSILON rgb 1 ]
[ 0*CellFactor + 3.5*NeighborFactor -EPSILON rgb 1 ]
[ 0*CellFactor + 3.5*NeighborFactor +EPSILON rgb 0 ]
// live cell
[ 1*CellFactor + 1.5*NeighborFactor -EPSILON rgb 0 ]
[ 1*CellFactor + 1.5*NeighborFactor +EPSILON rgb 1 ]
[ 1*CellFactor + 3.5*NeighborFactor -EPSILON rgb 1 ]
[ 1*CellFactor + 3.5*NeighborFactor +EPSILON rgb 0 ]
}
translate -<0.5,0.5,0>
}
#end
#local Tx1 = texture { pigment { PgNext translate <-1,-1, 0>*Delta }
finish { ambient NumLayers * NeighborFactor } }
#local Tx2 = texture { pigment { PgNext translate <-1, 0, 0>*Delta }
finish { ambient NumLayers * NeighborFactor } }
#local Tx3 = texture { pigment { PgNext translate <-1, 1, 0>*Delta }
finish { ambient NumLayers * NeighborFactor } }
#local Tx4 = texture { pigment { PgNext translate < 0,-1, 0>*Delta }
finish { ambient NumLayers * NeighborFactor } }
#local Tx5 = texture { pigment { PgNext translate < 0, 0, 0>*Delta }
finish { ambient NumLayers * CellFactor } }
#local Tx6 = texture { pigment { PgNext translate < 0, 1, 0>*Delta }
finish { ambient NumLayers * NeighborFactor } }
#local Tx7 = texture { pigment { PgNext translate < 1,-1, 0>*Delta }
finish { ambient NumLayers * NeighborFactor } }
#local Tx8 = texture { pigment { PgNext translate < 1, 0, 0>*Delta }
finish { ambient NumLayers * NeighborFactor } }
#local Tx9 = texture { pigment { PgNext translate < 1, 1, 0>*Delta }
finish { ambient NumLayers * NeighborFactor } }
#local TxOutput = texture {
average
texture_map {
[1 Tx1 ]
[1 Tx2 ]
[1 Tx3 ]
[1 Tx4 ]
[1 Tx5 ]
[1 Tx6 ]
[1 Tx7 ]
[1 Tx8 ]
[1 Tx9 ]
}
}
box { <-1.5, -0.5, 0.0>, <1.5, 0.5, 0.0> texture { TxOutput } }
--------------------------------------
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |