# HG changeset patch # User John Tsiombikas # Date 1355803989 -7200 # Node ID 9021a906c5d33700e3f1d370e3948aa0af3fc6fa # Parent a39c301cdcce8450f94157e1e5022201d72284d4 lots of stuff diff -r a39c301cdcce -r 9021a906c5d3 sdr/bloboray.p.glsl --- a/sdr/bloboray.p.glsl Sun Dec 16 14:24:16 2012 +0200 +++ b/sdr/bloboray.p.glsl Tue Dec 18 06:13:09 2012 +0200 @@ -12,32 +12,60 @@ float t0, t1; vec3 pos, normal; vec4 color; + vec3 refl; }; vec3 shade(Ray ray, HitPoint hit); -HitPoint intersect_voxels(Ray ray); +vec3 sky(Ray ray); +HitPoint ray_march(Ray ray); +float eval_blobs(vec3 pt); +vec3 calc_blob_normal(vec3 pt); HitPoint intersect_aabb(Ray ray, AABBox aabb); Ray get_primary_ray(float x, float y); +float luminance(vec3 col); +float fresnel(float r, float cosa); +vec3 get_blob(int i); -#define RAY_STEP 0.001 +#define BLOB_THRESHOLD 0.5 +#define BLOB_SCALE (1.0 / 4.0) +#define MAX_ITER 1 + +#define RAY_STEP (0.75 / volsize.z) #define FOV camprop.x #define ASPECT camprop.y uniform vec4 camprop; uniform vec3 volsize; uniform sampler3D voltex; +uniform vec3 worldsize; -//const vec3 worldsize = vec3(4.0, 4.0, 2.0); -const vec3 worldsize = vec3(1.0, 1.0, 0.5); +uniform sampler1D blobtex; +uniform int num_blobs; void main() { Ray ray = get_primary_ray(gl_TexCoord[0].x, gl_TexCoord[0].y); + HitPoint hit; vec3 color = vec3(0.0, 0.0, 0.0); - HitPoint hit = intersect_voxels(ray); - if(hit.hit) { - color = shade(ray, hit); + vec3 power = vec3(1.0, 1.0, 1.0); + + for(int i=0; i<=MAX_ITER; i++) { + hit = ray_march(ray); + if(hit.hit) { + color += shade(ray, hit) * power; + } else { + color += sky(ray) * power; + break; + } + + ray.origin = hit.pos + hit.normal * RAY_STEP; + ray.dir = reflect(ray.dir, hit.normal); + power *= hit.refl; + + if(luminance(power) < 0.075) { + break; + } } gl_FragColor = vec4(color, 1.0); @@ -55,9 +83,30 @@ float ndoth = max(dot(hit.normal, hvec), 0.0); vec3 diffuse = hit.color.xyz * ndotl; - vec3 specular = vec3(0.4, 0.4, 0.4) * pow(ndoth, 60.0); + vec3 specular = hit.refl * pow(ndoth, 60.0); - return diffuse + specular; + vec3 color = diffuse + specular; + + float fog = 0.0;//smoothstep(4.0, 8.0, hit.t0); + + //const float fog_density = 0.18; + //float fog = exp(-fog_density * fog_density * hit.t0 * hit.t0); + //fog = clamp(fog, 0.0, 1.0); + + return mix(color, sky(ray), fog); +} + +#define M_PI 3.141592653 + +vec3 sky(Ray ray) +{ + const vec3 horiz = vec3(0.64, 0.70, 0.76); + const vec3 zenith = vec3(0.65, 0.82, 0.94); + + float angle = acos(ray.dir.y); + float t = 1.0 - angle / (M_PI / 2.0); + + return mix(horiz, zenith, smoothstep(-0.2, 0.2, t)); } vec4 fetch_voxel(vec3 pt) @@ -68,7 +117,7 @@ vec3 calc_voxel_normal(vec3 pt) { - vec3 offs = 1.8 / volsize; + vec3 offs = 6.0 / volsize; float dfdx = fetch_voxel(pt + vec3(offs.x, 0.0, 0.0)).w - fetch_voxel(pt - vec3(offs.x, 0.0, 0.0)).w; float dfdy = fetch_voxel(pt + vec3(0.0, offs.y, 0.0)).w - fetch_voxel(pt - vec3(0.0, offs.y, 0.0)).w; float dfdz = fetch_voxel(pt + vec3(0.0, 0.0, offs.z)).w - fetch_voxel(pt - vec3(0.0, 0.0, offs.z)).w; @@ -76,12 +125,17 @@ return -normalize(vec3(dfdx, dfdy, dfdz)); } -HitPoint intersect_voxels(Ray ray) +HitPoint ray_march(Ray ray) { HitPoint hit; //AABBox aabb = AABBox(vec3(-1.0, -1.0, -1.0), vec3(1.0, 1.0, 1.0)); AABBox aabb = AABBox(-worldsize.xzy, worldsize.xzy); + hit.hit = false; + hit.t0 = hit.t1 = 0.0; + hit.pos = hit.normal = vec3(0.0, 0.0, 0.0); + hit.color = vec4(1.0, 1.0, 1.0, 1.0); + hit = intersect_aabb(ray, aabb); if(!hit.hit) { @@ -96,14 +150,25 @@ while(dist < end_dist) { vec3 pt = ray.origin + ray.dir * dist; + + // first try evaluating the blob field at this point + float blob = eval_blobs(pt); + if(blob >= BLOB_THRESHOLD) { + hit.t0 = dist; + hit.pos = pt; + hit.normal = calc_blob_normal(pt); + hit.color = vec4(0.0, 0.0, 0.0, 1.0); + hit.refl = vec3(1.0, 0.9, 0.75); + return hit; + } + vec4 voxel = fetch_voxel(pt.xzy); - - if(voxel.a > 0.5) { hit.t0 = dist; hit.pos = pt; hit.normal = calc_voxel_normal(pt.xzy).xzy; hit.color = voxel; + hit.refl = vec3(0.0, 0.0, 0.0); return hit; } @@ -114,24 +179,48 @@ return hit; } +float eval_blobs(vec3 pt) +{ + float val = 0.0; + + for(int i=0; iworld_size = Vector3(8, 8, 4); level->generate(); printf("initializing renderer\n"); @@ -44,6 +48,11 @@ cam.input_move(0, 2, 2); cam.input_rotate(0, M_PI / 5, 0); + glClearColor(fog_color[0], fog_color[1], fog_color[2], 1.0); + glFogfv(GL_FOG_COLOR, fog_color); + + gravity = Vector3(0, -0.01, 0); + return true; } @@ -73,6 +82,18 @@ } cam.input_move(dx, 0, dy); + + for(size_t i=0; iblobs.size(); i++) { + Blob *b = &level->blobs[i]; + + b->velocity += gravity * dt; + Vector3 npos = b->pos + b->velocity * dt; + + Vector3 normal; + if(level->collision(b->pos, npos, &npos, &normal)) { + b->velocity = b->velocity.reflection(normal); + } + } } void game_render() @@ -81,6 +102,7 @@ if(opt.stereo) { glDrawBuffer(GL_BACK_LEFT); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); @@ -92,6 +114,7 @@ rend->render(); glDrawBuffer(GL_BACK_RIGHT); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); @@ -102,6 +125,8 @@ rend->render(); } else { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glMatrixMode(GL_PROJECTION); glLoadIdentity(); proj_matrix(0); diff -r a39c301cdcce -r 9021a906c5d3 src/level.cc --- a/src/level.cc Sun Dec 16 14:24:16 2012 +0200 +++ b/src/level.cc Tue Dec 18 06:13:09 2012 +0200 @@ -5,6 +5,7 @@ Level::Level() { terrain = 0; + world_size = Vector3(1, 1, 1); } Level::~Level() @@ -19,7 +20,7 @@ float valley = nx * nx + ny * ny; float s = opt.gen_noise_scale; - float noise = 0.2 * fbm2(x * s, y * s, 3) * (valley + 0.25); + float noise = 0.2 * fbm2(x * s, y * s, 4) * (valley + 0.25); float grad = 0.75 - z + noise + valley * 0.4; return grad; @@ -56,7 +57,7 @@ } else if(z < 0.8) { if(alpha < 0.56) { // grass - voxel = Vector4(0.68, 0.95, 0.38); + voxel = Vector4(0.49, 0.72, 0.48); } else { // mud voxel = Vector4(0.57, 0.43, 0.29, 1); @@ -68,6 +69,14 @@ } } } + + // generate some blobs + for(int i=0; i (b) ? (b) : (x))) + +const Vector4 &Level::get_voxel(const Vector3 &pos) const +{ + Vector3 p = pos / world_size + Vector3(0.5, 0.5, 0.5); + + int xsz = terrain->get_size(0); + int ysz = terrain->get_size(1); + int zsz = terrain->get_size(2); + + int i = (int)(p.x * xsz); + int j = (int)(p.y * ysz); + int k = (int)(p.z * zsz); + + return terrain->get_voxel(CLAMP(i, 0, xsz - 1), CLAMP(j, 0, ysz - 1), CLAMP(k, 0, zsz - 1)); +} + +Vector3 Level::calc_normal(const Vector3 &pos) const +{ + int xsz = terrain->get_size(0); + int ysz = terrain->get_size(1); + int zsz = terrain->get_size(2); + + float dx = world_size.x / (float)xsz; + float dy = world_size.y / (float)ysz; + float dz = world_size.z / (float)zsz; + + float dfdx = get_voxel(pos + Vector3(dx, 0, 0)).w - get_voxel(pos - Vector3(dx, 0, 0)).w; + float dfdy = get_voxel(pos + Vector3(0, dy, 0)).w - get_voxel(pos - Vector3(0, dy, 0)).w; + float dfdz = get_voxel(pos + Vector3(0, 0, dz)).w - get_voxel(pos - Vector3(0, 0, dz)).w; + + return Vector3(dfdx, dfdy, dfdz); +} + +bool Level::collision(const Vector3 &pos0, const Vector3 &pos1, Vector3 *outpos, Vector3 *outnorm) const +{ + Vector4 vox0 = get_voxel(pos0); + Vector4 vox1 = get_voxel(pos1); + + if(vox0.w < 0.5 && vox1.w >= 0.5) { + *outpos = lerp(pos0, pos1, 0.5); // TODO + *outnorm = calc_normal(*outpos); + return true; + } + return false; +} diff -r a39c301cdcce -r 9021a906c5d3 src/level.h --- a/src/level.h Sun Dec 16 14:24:16 2012 +0200 +++ b/src/level.h Tue Dec 18 06:13:09 2012 +0200 @@ -4,10 +4,17 @@ #include #include "volume.h" +struct Blob { + Vector3 pos; + Vector3 velocity; +}; + class Level { public: Volume *terrain; - std::vector blobs; + std::vector blobs; + + Vector3 world_size; Level(); ~Level(); @@ -16,6 +23,11 @@ bool load(const char *fname); bool save(const char *fname) const; + + const Vector4 &get_voxel(const Vector3 &pos) const; + Vector3 calc_normal(const Vector3 &pos) const; + + bool collision(const Vector3 &pos0, const Vector3 &pos1, Vector3 *outpos, Vector3 *outnorm) const; }; #endif // LEVEL_H_ diff -r a39c301cdcce -r 9021a906c5d3 src/main.cc --- a/src/main.cc Sun Dec 16 14:24:16 2012 +0200 +++ b/src/main.cc Tue Dec 18 06:13:09 2012 +0200 @@ -63,7 +63,6 @@ game_iter((msec - prev_msec) / 1000.0); prev_msec = msec; - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); game_render(); diff -r a39c301cdcce -r 9021a906c5d3 src/opt.cc --- a/src/opt.cc Sun Dec 16 14:24:16 2012 +0200 +++ b/src/opt.cc Tue Dec 18 06:13:09 2012 +0200 @@ -15,6 +15,7 @@ opt.world_size[2] = 64; opt.gen_noise_scale = 1.0f; + opt.gen_num_blobs = 10; } bool parse_opt(int argc, char **argv) @@ -40,6 +41,13 @@ fprintf(stderr, "-genscale must be followed by a scaling factor\n"); return false; } + } else if(strcmp(argv[i], "-blobs") == 0) { + char *endp; + opt.gen_num_blobs = strtol(argv[++i], &endp, 10); + if(endp == argv[i]) { + fprintf(stderr, "-blobs must be followed by the number of blobs\n"); + return false; + } } else if(strcmp(argv[i], "-stereo") == 0) { opt.stereo = true; } else { diff -r a39c301cdcce -r 9021a906c5d3 src/opt.h --- a/src/opt.h Sun Dec 16 14:24:16 2012 +0200 +++ b/src/opt.h Tue Dec 18 06:13:09 2012 +0200 @@ -8,6 +8,7 @@ // initial parameters when generating new worlds int world_size[3]; float gen_noise_scale; + int gen_num_blobs; }; extern Options opt; diff -r a39c301cdcce -r 9021a906c5d3 src/renderer.cc --- a/src/renderer.cc Sun Dec 16 14:24:16 2012 +0200 +++ b/src/renderer.cc Tue Dec 18 06:13:09 2012 +0200 @@ -4,6 +4,7 @@ Renderer::Renderer() { + blobtex = 0; leveltex = 0; sdrprog = 0; @@ -29,6 +30,10 @@ leveltex = new Texture3D; leveltex->create(vol->get_size(0), vol->get_size(1), vol->get_size(2)); + blobtex = new Texture1D; + blobtex->create(level->blobs.size()); + blobtex->set_filtering(GL_NEAREST); + this->level = level; return true; @@ -57,11 +62,19 @@ void Renderer::render() const { leveltex->update((float*)level->terrain->get_data_ptr()); - bind_texture(leveltex); + ((Renderer*)this)->update_blobtex(); + bind_texture(leveltex, 0); + bind_texture(blobtex, 1); + + set_uniform_float3(sdrprog, "worldsize", level->world_size.x, level->world_size.y, + level->world_size.z); set_uniform_float3(sdrprog, "volsize", level->terrain->get_size(0), level->terrain->get_size(1), level->terrain->get_size(2)); set_uniform_float4(sdrprog, "camprop", fov, aspect, 0, 0); + + set_uniform_int(sdrprog, "voltex", 0); + set_uniform_int(sdrprog, "blobtex", 1); bind_program(sdrprog); glBegin(GL_QUADS); @@ -76,7 +89,8 @@ glEnd(); bind_program(0); - bind_texture(0); + bind_texture(0, 1); + bind_texture(0, 0); /*glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); @@ -147,3 +161,20 @@ glVertex3f(pos.x - sz, pos.y - sz, pos.z + sz); } + +void Renderer::update_blobtex() +{ + int nblobs = (int)level->blobs.size(); + + float *data = (float*)alloca(nblobs * 4 * sizeof *data); + float *dptr = data; + + for(int i=0; iblobs[i].pos.x; + *dptr++ = level->blobs[i].pos.y; + *dptr++ = level->blobs[i].pos.z; + *dptr++ = 1.0; + } + + blobtex->update(data); +} diff -r a39c301cdcce -r 9021a906c5d3 src/renderer.h --- a/src/renderer.h Sun Dec 16 14:24:16 2012 +0200 +++ b/src/renderer.h Tue Dec 18 06:13:09 2012 +0200 @@ -7,11 +7,14 @@ class Renderer { private: Level *level; + Texture1D *blobtex; Texture3D *leveltex; unsigned int sdrprog; float fov, aspect; + void update_blobtex(); + public: Renderer(); ~Renderer(); diff -r a39c301cdcce -r 9021a906c5d3 src/texture.cc --- a/src/texture.cc Sun Dec 16 14:24:16 2012 +0200 +++ b/src/texture.cc Tue Dec 18 06:13:09 2012 +0200 @@ -38,11 +38,53 @@ } } +void Texture::set_filtering(unsigned int min_filter, unsigned int mag_filter) +{ + if(mag_filter == 0) { + mag_filter = min_filter; + } + + glBindTexture(type, tex); + glTexParameteri(type, GL_TEXTURE_MIN_FILTER, min_filter); + glTexParameteri(type, GL_TEXTURE_MAG_FILTER, mag_filter); +} + +void Texture::set_wrapping(unsigned int wrap) +{ + glBindTexture(type, tex); + glTexParameteri(type, GL_TEXTURE_WRAP_S, wrap); + glTexParameteri(type, GL_TEXTURE_WRAP_T, wrap); + glTexParameteri(type, GL_TEXTURE_WRAP_R, wrap); +} + int Texture::get_size(int idx) const { return idx >= 0 && idx < 3 ? size[idx] : 0; } +Texture1D::Texture1D() +{ + type = GL_TEXTURE_1D; + + glBindTexture(type, tex); + glTexParameteri(type, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(type, GL_TEXTURE_MAG_FILTER, GL_LINEAR); +} + +void Texture1D::create(int sz, float *data) +{ + glBindTexture(type, tex); + glTexImage1D(type, 0, GL_RGBA, sz, 0, GL_RGBA, GL_FLOAT, data); + + size[0] = sz; +} + +void Texture1D::update(float *data) +{ + glBindTexture(type, tex); + glTexSubImage1D(type, 0, 0, size[0], GL_RGBA, GL_FLOAT, data); +} + Texture2D::Texture2D() { type = GL_TEXTURE_2D; diff -r a39c301cdcce -r 9021a906c5d3 src/texture.h --- a/src/texture.h Sun Dec 16 14:24:16 2012 +0200 +++ b/src/texture.h Tue Dec 18 06:13:09 2012 +0200 @@ -12,6 +12,9 @@ Texture(); virtual ~Texture(); + virtual void set_filtering(unsigned int min_filter, unsigned int mag_filter = 0); + virtual void set_wrapping(unsigned int wrap); + virtual int get_size(int idx) const; virtual void update(float *data) = 0; @@ -21,6 +24,15 @@ void bind_texture(const Texture *tex, int texunit = 0); +class Texture1D : public Texture { +public: + Texture1D(); + + void create(int sz, float *data = 0); + + void update(float *data); +}; + class Texture2D : public Texture { public: Texture2D();