From 51d4f8162df01225e096d24971e8c8335b8c8371 Mon Sep 17 00:00:00 2001 From: Adrian Kummerlaender Date: Fri, 3 Jan 2020 14:09:40 +0100 Subject: Improve structure, play around with phase functions --- bluedot.py | 15 ++++++++------ planets.py | 6 ++++-- raymarch.cl | 65 +++++++++++++++++++++++++++++++++---------------------------- sunrise.py | 25 ++++++++++++++---------- 4 files changed, 63 insertions(+), 48 deletions(-) diff --git a/bluedot.py b/bluedot.py index 036ae7f..4b906a8 100644 --- a/bluedot.py +++ b/bluedot.py @@ -17,11 +17,14 @@ config = { 'light_samples': 8, 'exposure': 20.0, + 'zoom': 2.0, - 'eye_pos': (0, -3, 1.1), - 'eye_dir': (0, 1, -0.35) + 'eye_pos': numpy.array([0, -3, 1.1]), + 'eye_dir': numpy.array([0, 1, -0.35]) } +sun_range = (0, 360, 1) + cl_platform = cl.get_platforms()[0] cl_context = cl.Context(properties=[(cl.context_properties.PLATFORM, cl_platform)]) cl_queue = cl.CommandQueue(cl_context) @@ -34,17 +37,17 @@ with open('raymarch.cl') as f: {**config, **earth} )).build() -for i in range(0,360): +for i in numpy.arange(*sun_range): sun = make_double3(numpy.cos(i*2*numpy.pi/360),numpy.sin(i*2*numpy.pi/360),0) print(sun) program.render( cl_queue, (config['size_x'], config['size_y']), None, cl_picture, - make_double3(*config['eye_pos']), - make_double3(*config['eye_dir']), + make_double3(*(config['eye_pos'] * earth['earth_radius'])), + make_double3(*(config['eye_dir'] * earth['earth_radius'])), sun) np_picture = numpy.ndarray(shape=(config['size_y'], config['size_x'], 3), dtype=numpy.float64) cl.enqueue_copy(cl_queue, np_picture, cl_picture).wait(); - plt.imsave('sky_%03d.png' % i, np_picture, origin='lower') + plt.imsave("bluedot_%05.1f.png" % i, np_picture, origin='lower') diff --git a/planets.py b/planets.py index f94782c..1d955f5 100644 --- a/planets.py +++ b/planets.py @@ -5,6 +5,8 @@ earth = { 'rayleigh_atmos_height': 7994, 'mie_atmos_height' : 1200, - 'rayleigh_beta': (3.8e-6, 13.5e-6, 33.1e-6), - 'mie_beta' : (21e-6) + 'rayleigh_beta': (5.196e-6, 12.142e-6, 29.645e-6), + #'rayleigh_beta': (3.8e-6, 13.5e-6, 33.1e-6), + 'mie_beta' : (21e-6), + 'mie_g' : 0.75 } diff --git a/raymarch.cl b/raymarch.cl index d6a771d..391d844 100644 --- a/raymarch.cl +++ b/raymarch.cl @@ -1,11 +1,9 @@ __constant double earth_radius = $earth_radius; __constant double atmos_height = $atmos_height; -__constant double rayleigh_atmos_height = $rayleigh_atmos_height; -__constant double mie_atmos_height = $mie_atmos_height; - __constant double3 rayleigh_beta = (double3)$rayleigh_beta; __constant double3 mie_beta = (double3)$mie_beta; +__constant double mie_g = $mie_g; __constant int ray_samples = $ray_samples; __constant int light_samples = $light_samples; @@ -20,7 +18,7 @@ double altitude(double3 pos) { return length(pos) - earth_radius; } -// solve x^2 + px + q +/// Solve x^2 + px + q bool solvePolynomialOfDegreeTwo(double p, double q, double* x1, double* x2) { const double pHalf = 0.5*p; const double inner = pHalf*pHalf - q; @@ -34,7 +32,7 @@ bool solvePolynomialOfDegreeTwo(double p, double q, double* x1, double* x2) { } } -// interection of origin + d*dir and a sphere of radius r for normalized dir +/// Interection of origin + d*dir and a sphere of radius r for normalized dir bool solveRaySphereIntersection(double3 origin, double3 dir, double r, double* d0, double* d1) { const double p = 2 * dot(dir,origin); const double q = dot(origin,origin) - r*r; @@ -51,6 +49,7 @@ bool solveRaySphereIntersection(double3 origin, double3 dir, double r, double* d } } +/// Map {0,...,screenX}x{0,...,screenY} to [-1,1]^2 double2 getNormalizedScreenPos(double x, double y) { return (double2)( 2.0 * (x / $size_x - 0.5) * $size_x.0 / $size_y.0, @@ -58,26 +57,44 @@ double2 getNormalizedScreenPos(double x, double y) { ); } +/// Pinhole camera double3 getEyeRayDir(double2 screen_pos, double3 eye_pos, double3 eye_target) { const double3 forward = normalize(eye_target - eye_pos); const double3 right = normalize(cross((double3)(0.0, 0.0, 1.0), forward)); const double3 up = normalize(cross(forward, right)); - return normalize(screen_pos.x*right + screen_pos.y*up + 1.5*forward); + return normalize(screen_pos.x*right + screen_pos.y*up + $zoom*forward); } +/// Return true iff earth is hit by rays along dir bool isVisible(double3 origin, double3 dir) { double e0, e1; return !solveRaySphereIntersection(origin, dir, earth_radius, &e0, &e1) || (e0 < 0 && e1 < 0); } +/// Return distance between entering and exiting the atmosphere double lengthOfRayInAtmosphere(double3 origin, double3 dir) { double d0, d1; solveRaySphereIntersection(origin, dir, earth_radius + atmos_height, &d0, &d1); return d1 - d0; } +/// Return light depths of secondary rays +double2 lightDepth(double3 curr, double3 sun) { + const double h = lengthOfRayInAtmosphere(curr, sun) / light_samples; + + double2 depth = 0.0; + + for (unsigned i = 0; i < light_samples; ++i) { + const double height = altitude(curr + (i+0.5)*h*sun); + depth += exp(-height / (double2)($rayleigh_atmos_height, $mie_atmos_height)) * h; + } + + return depth; +} + +/// Calculate color of light along ray double3 scatter(double3 origin, double3 dir, double dist, double3 sun) { double3 rayleigh_sum = 0.0; double3 mie_sum = 0.0; @@ -87,32 +104,22 @@ double3 scatter(double3 origin, double3 dir, double dist, double3 sun) { const double h = dist / ray_samples; - for (int i = 0; i < ray_samples; ++i) { + for (unsigned i = 0; i < ray_samples; ++i) { double3 curr = origin + (i+0.5)*h*dir; if (isVisible(curr, sun)) { - double height = altitude(curr); + const double height = altitude(curr); - double rayleigh_h = exp(-height / rayleigh_atmos_height) * h; - double mie_h = exp(-height / mie_atmos_height) * h; + const double rayleigh_h = exp(-height / $rayleigh_atmos_height) * h; + const double mie_h = exp(-height / $mie_atmos_height) * h; rayleigh_depth += rayleigh_h; mie_depth += mie_h; - double light_h = lengthOfRayInAtmosphere(curr, sun) / light_samples; - - double rayleigh_light_depth = 0; - double mie_light_depth = 0; - - for (int j = 0; j < light_samples; ++j) { - height = altitude(curr + (j+0.5)*light_h*sun); - - rayleigh_light_depth += exp(-height / rayleigh_atmos_height) * light_h; - mie_light_depth += exp(-height / mie_atmos_height) * light_h; - } - - double3 tau = rayleigh_beta*(rayleigh_depth+rayleigh_light_depth) + mie_beta*(mie_depth+ mie_light_depth); - double3 attenuation = exp(-tau); + const double2 light_depth = lightDepth(curr, sun); + const double3 tau = rayleigh_beta * (rayleigh_depth + light_depth[0]) + + mie_beta * (mie_depth + light_depth[1]); + const double3 attenuation = exp(-tau); rayleigh_sum += attenuation * rayleigh_h; mie_sum += attenuation * mie_h; @@ -120,9 +127,10 @@ double3 scatter(double3 origin, double3 dir, double dist, double3 sun) { } const double mu = dot(dir,sun); - const double rayleigh_phase = 3. / (16.*M_PI) * (1.0 + mu*mu); - const double g = 0.8; - const double mie_phase = 3. / (8.*M_PI) * ((1. - g*g) * (1. + mu*mu)) / ((2. + g*g) * pow(1. + g*g - 2.*g*mu, 1.5)); + + const double rayleigh_phase = 3./(16.*M_PI) * (1.0 + mu*mu); + const double mie_phase = (3.*(1. - mie_g*mie_g)) / (2.*(2. + mie_g*mie_g)) * (1. + mu*mu) / pow(1. + mie_g*mie_g - 2.*mie_g*mu, 1.5); + //const double mie_phase = (1-mie_g*mie_g) / (4*M_PI*pow(1+mie_g*mie_g-2*mie_g*mu,1.5)); return rayleigh_sum*rayleigh_beta*rayleigh_phase + mie_sum*mie_beta*mie_phase; } @@ -134,9 +142,6 @@ void setColor(__global double* result, unsigned x, unsigned y, double3 color) { } __kernel void render(__global double* result, double3 eye_pos, double3 eye_dir, double3 sun) { - eye_pos *= earth_radius; - eye_dir *= earth_radius; - const unsigned x = get_global_id(0); const unsigned y = get_global_id(1); diff --git a/sunrise.py b/sunrise.py index b7b2cd3..9a99605 100644 --- a/sunrise.py +++ b/sunrise.py @@ -10,18 +10,21 @@ mf = cl.mem_flags from planets import earth config = { - 'size_x': 480, - 'size_y': 270, + 'size_x': 1920//4, + 'size_y': 1080//4, - 'ray_samples' : 64, - 'light_samples': 32, + 'ray_samples' : 32, + 'light_samples': 8, 'exposure': 20.0, + 'zoom': 1.0, - 'eye_pos': (0, 0, 1.00001), - 'eye_dir': (0, 1, 0.3) + 'eye_pos': numpy.array([0, 0, 1.0001]), + 'eye_dir': numpy.array([0, 1, 0]) } +sun_range = (-10, 90, 10) + cl_platform = cl.get_platforms()[0] cl_context = cl.Context(properties=[(cl.context_properties.PLATFORM, cl_platform)]) cl_queue = cl.CommandQueue(cl_context) @@ -29,22 +32,24 @@ cl_queue = cl.CommandQueue(cl_context) cl_picture = cl.Buffer(cl_context, mf.WRITE_ONLY, size=config['size_x']*config['size_y']*3*numpy.float64(0).nbytes) program = None +print('height: %d' % (earth['earth_radius']*config['eye_pos'][2] - earth['earth_radius'])) + with open('raymarch.cl') as f: program = cl.Program(cl_context, Template(f.read()).substitute( {**config, **earth} )).build() -for i in range(-10,10): +for i in numpy.arange(*sun_range): sun = make_double3(0.0,numpy.cos(i*2*numpy.pi/360),numpy.sin(i*2*numpy.pi/360)) print(sun) program.render( cl_queue, (config['size_x'], config['size_y']), None, cl_picture, - make_double3(*config['eye_pos']), - make_double3(*config['eye_dir']), + make_double3(*(config['eye_pos'] * earth['earth_radius'])), + make_double3(*(config['eye_dir'] * earth['earth_radius'])), sun) np_picture = numpy.ndarray(shape=(config['size_y'], config['size_x'], 3), dtype=numpy.float64) cl.enqueue_copy(cl_queue, np_picture, cl_picture).wait(); - plt.imsave('sky_%03d.png' % (i+10), np_picture, origin='lower') + plt.imsave("sky_%05.1f.png" % (i-sun_range[0]), np_picture, origin='lower') -- cgit v1.2.3