N-Body dynamics
d^{ 2}r_{i} / dt^{ 2} = F_{i} = G m ∑_{ k} (r_{k} - r_{i }) / |r_{k} - r_{i}|^{3} for N = 4096 are simulated. We put G m = 1 by the time scaling. Explicit scheme r^{ t+2} = 2 r^{ t+1} - r^{ t} + F^{ t+1} Δt^{2} with constant time step Δt is used. |
See also N = 8K simulation. I can't make a spiral galaxy (I'm not an expert :)
N = | 4096 | 16K | 32K |
HD 4870 | 1200=20×60 20 |
80=4×20 21.5 | 21=2.1×10 22.5 |
HD 4650 | 420=21×20 7 |
28=14×2 7.5 | 5=2.5×2 5.4 |
HD 4870 800 shaders, 790gpu/1100mem MHz, 256 bit bus width,
GDDR5 memory
HD 4650 320 shaders, 712gpu/550mem MHz, 128 bit bus width, GDDR3 memory
Numbers: shaders power ratio is 800×790 / 320×712 = 2.8 and performance ratio is 20/7 = 2.9 so GDDR3 memory bandwidth is not a bottleneck in this simulation!
<script id="shader-fs" type="x-shader/x-fragment"> #ifdef GL_ES precision highp float; #endif uniform sampler2D samp; uniform sampler2D samp1; varying vec2 vTexCoord; const float d = 1./64., e2 = .01, dt2 = .00001; void main(void) { vec3 r = texture2D(samp, vTexCoord).xyz; vec3 r1 = texture2D(samp1, vTexCoord).xyz; vec3 f = vec3( 0. ); for(float y = 0.; y < 1.; y += d ){ for(float x = 0.; x < 1.; x += d ){ vec3 v = texture2D(samp1, vTexCoord + vec2(x, y)).xyz - r1; float a = dot(v, v) + e2; f += v/(a*sqrt(a)); } } r = 2.*r1 - r + f*dt2; gl_FragColor = vec4(r, 0. ); } </script>This vertex script renders the 2×2 square into FBO to make computations for every pixel in textures.
<script id="shader-vs" type="x-shader/x-vertex"> attribute vec2 aPos; attribute vec2 aTexCoord; varying vec2 vTexCoord; void main(void) { gl_Position = vec4(aPos, 0., 1.); vTexCoord = aTexCoord; } </script>N points square lattice is used to show the bodies in the shader below
<script id="shader-vs-show" type="x-shader/x-vertex"> attribute vec2 aPoints; uniform mat4 mvMatrix; uniform mat4 prMatrix; uniform sampler2D uTexSamp; varying vec4 color; void main(void) { gl_Position = prMatrix * mvMatrix * texture2D(uTexSamp, aPoints ); color = vec4( 1.); } </script>Computations are organized by the function
function draw(){ gl.viewport(0, 0, 64, 64); gl.useProgram(prog); for(var i = 0; i < it; i++){ gl.uniform1i(sampLoc, 0); gl.uniform1i(samp1Loc, 1); gl.bindFramebuffer(gl.FRAMEBUFFER, FBO2); gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); gl.uniform1i(sampLoc, 1); gl.uniform1i(samp1Loc, 2); gl.bindFramebuffer(gl.FRAMEBUFFER, FBO); gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); gl.uniform1i(sampLoc, 2); gl.uniform1i(samp1Loc, 0); gl.bindFramebuffer(gl.FRAMEBUFFER, FBO1); gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); } drawScene(); frames++; }at last drawScene() prepares transformations and executes
gl.drawArrays(gl.POINTS, 0, 64*64);to show scene.
[1]
GPU Gems 3. Chapter 31. Fast N-Body Simulation with CUDA
L.Nyland, M.Harris, J.Prins
[2] Kazuki Fujiwara, Naohito Nakasato
Fast Simulations of Gravitational Many-body Problem on RV770 GPU
arXiv:0904.3659v1
[3] S.F.P.Zwart, R.G.Belleman, P.M.Geldof
High-performance direct gravitational N-body simulations
on graphics processing units. New Astronomy 12 (2007) 641-650
[4]
Vanderbei's N-Body Page 1000 "Star Clusters" Java simulation
[5] WebGL Orrery by Ilmari Heikkinen