ld33_umonster
changeset 7:92d662deb66e
capsule distance seems broken
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Tue, 25 Aug 2015 00:38:00 +0300 |
parents | 3b4460b34d43 |
children | bed39534d471 |
files | Makefile sdr/shadow.v.glsl src/dragon.cc src/dragon.h src/game.cc src/geom.cc src/geom.h |
diffstat | 7 files changed, 291 insertions(+), 43 deletions(-) [+] |
line diff
1.1 --- a/Makefile Sun Aug 23 05:37:09 2015 +0300 1.2 +++ b/Makefile Tue Aug 25 00:38:00 2015 +0300 1.3 @@ -9,11 +9,11 @@ 1.4 1.5 warn = -pedantic -Wall -Wno-format-extra-args 1.6 dbg = -g 1.7 -opt = -O0 1.8 +opt = -O3 1.9 1.10 CFLAGS = $(warn) $(dbg) $(opt) 1.11 CXXFLAGS = $(CFLAGS) 1.12 -LDFLAGS = $(libgl) -lvmath -limago -lpsys -lanim -lm 1.13 +LDFLAGS = $(libgl) -lvmath -limago -lpsys -lanim -lm -lmetasurf 1.14 1.15 ifeq ($(sys), Darwin) 1.16 libgl = -framework OpenGL -framework GLUT -lGLEW
2.1 --- a/sdr/shadow.v.glsl Sun Aug 23 05:37:09 2015 +0300 2.2 +++ b/sdr/shadow.v.glsl Tue Aug 25 00:38:00 2015 +0300 2.3 @@ -6,7 +6,7 @@ 2.4 gl_Position = ftransform(); 2.5 2.6 vec3 vpos = (gl_ModelViewMatrix * gl_Vertex).xyz; 2.7 - normal = gl_NormalMatrix * gl_Normal; 2.8 + normal = normalize(gl_NormalMatrix * gl_Normal); 2.9 vdir = -vpos; 2.10 ldir = gl_LightSource[0].position.xyz - vpos; 2.11 gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
3.1 --- a/src/dragon.cc Sun Aug 23 05:37:09 2015 +0300 3.2 +++ b/src/dragon.cc Tue Aug 25 00:38:00 2015 +0300 3.3 @@ -1,15 +1,60 @@ 3.4 #include <algorithm> 3.5 #include "opengl.h" 3.6 #include "dragon.h" 3.7 +#include "metasurf.h" 3.8 +#include "geom.h" 3.9 +#include "game.h" 3.10 +#include "shadow.h" 3.11 + 3.12 +#define VOXEL_PAD 1.0f 3.13 +#define DYN_FCOUNT 64 3.14 +#define DYN_VCOUNT (DYN_FCOUNT * 3) 3.15 + 3.16 +#define NUM_NECK_SEG 8 3.17 +static const float nseg_sizes[NUM_NECK_SEG][2] = { 3.18 + {1.0, 3.0}, {1.0, 1.5}, {1.5, 2.0}, {2.0, 2.5}, {2.5, 3.0}, {3.0, 3.5} 3.19 +}; 3.20 + 3.21 +static Vector3 bezier(const Vector3 &a, const Vector3 &b, const Vector3 &c, const Vector3 &d, float t); 3.22 +static float mseval(struct metasurface *ms, float x, float y, float z); 3.23 +static void msvertex(struct metasurface *ms, float x, float y, float z); 3.24 + 3.25 3.26 Dragon::Dragon() 3.27 : pos(0, 0, 0), dir(0, 0, -1), head_pos(0, 0, -1), target(0, 0, -2) 3.28 { 3.29 set_head_limits(-1, 1, -1, 1); 3.30 + 3.31 + glGenBuffers(1, &dyn_vbo); 3.32 + glBindBuffer(GL_ARRAY_BUFFER, dyn_vbo); 3.33 + glBufferData(GL_ARRAY_BUFFER, DYN_VCOUNT * sizeof(DynVertex), 0, GL_STREAM_DRAW); 3.34 + glBindBuffer(GL_ARRAY_BUFFER, 0); 3.35 + 3.36 + dyn_varr = new DynVertex[DYN_VCOUNT]; 3.37 + 3.38 + neck_seg_count = NUM_NECK_SEG; 3.39 + neck_seg = new Capsule[neck_seg_count]; 3.40 + 3.41 + for(int i=0; i<neck_seg_count; i++) { 3.42 + neck_seg[i].w[0] = nseg_sizes[i][0]; 3.43 + neck_seg[i].w[1] = nseg_sizes[i][1]; 3.44 + } 3.45 + 3.46 + msurf = msurf_create(); 3.47 + msurf_set_user_data(msurf, this); 3.48 + msurf_set_resolution(msurf, 36, 36, 36); 3.49 + msurf_set_threshold(msurf, 1.0); 3.50 + msurf_eval_func(msurf, mseval); 3.51 + msurf_vertex_func(msurf, msvertex); 3.52 } 3.53 3.54 Dragon::~Dragon() 3.55 { 3.56 + delete [] neck_seg; 3.57 + msurf_free(msurf); 3.58 + 3.59 + delete [] dyn_varr; 3.60 + glDeleteBuffers(1, &dyn_vbo); 3.61 } 3.62 3.63 void Dragon::set_position(const Vector3 &p) 3.64 @@ -71,8 +116,120 @@ 3.65 3.66 void Dragon::update() 3.67 { 3.68 + Vector3 bdir = breath_dir(); 3.69 + Vector3 bezcp[] = { pos, pos + dir * 6.0, head_pos - bdir * 8.0, head_pos }; 3.70 + 3.71 + float t = 0.0, dt = 1.0 / (float)(neck_seg_count + 1); 3.72 + Vector3 p = bezier(bezcp[0], bezcp[1], bezcp[2], bezcp[3], t); 3.73 + 3.74 + for(int i=0; i<neck_seg_count; i++) { 3.75 + t += dt; 3.76 + Vector3 pnext = bezier(bezcp[0], bezcp[1], bezcp[2], bezcp[3], t); 3.77 + 3.78 + neck_seg[i].p[0] = p; 3.79 + neck_seg[i].p[1] = pnext; 3.80 + 3.81 + p = pnext; 3.82 + } 3.83 } 3.84 3.85 +void Dragon::draw() const 3.86 +{ 3.87 + static float bmin[] = { head_xlim[0] - VOXEL_PAD * 0.9, head_ylim[0] - VOXEL_PAD, head_pos.z }; 3.88 + static float bmax[] = { head_xlim[1] + VOXEL_PAD * 0.9, head_ylim[1] + VOXEL_PAD * 2.1f, pos.z + VOXEL_PAD }; 3.89 + msurf_set_bounds(msurf, bmin[0], bmin[1], bmin[2], bmax[0], bmax[1], bmax[2]); 3.90 + 3.91 + 3.92 + if(!shadow_pass) { 3.93 + 3.94 + if(dbg_wireframe) { 3.95 + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); 3.96 + } 3.97 + 3.98 + dyn_vidx = 0; 3.99 + msurf_polygonize(msurf); 3.100 + flush_dynvbo(); 3.101 + 3.102 + if(dbg_wireframe) { 3.103 + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 3.104 + } 3.105 + 3.106 + int cur_sdr; 3.107 + glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr); 3.108 + glUseProgram(0); 3.109 + 3.110 + glPushAttrib(GL_ENABLE_BIT); 3.111 + glDisable(GL_LIGHTING); 3.112 + 3.113 + // bounds 3.114 + glColor3f(1, 0, 0); 3.115 + glBegin(GL_LINE_LOOP); 3.116 + glVertex3f(bmin[0], bmin[1], bmin[2]); 3.117 + glVertex3f(bmax[0], bmin[1], bmin[2]); 3.118 + glVertex3f(bmax[0], bmax[1], bmin[2]); 3.119 + glVertex3f(bmin[0], bmax[1], bmin[2]); 3.120 + glEnd(); 3.121 + glBegin(GL_LINE_LOOP); 3.122 + glVertex3f(bmin[0], bmin[1], bmax[2]); 3.123 + glVertex3f(bmax[0], bmin[1], bmax[2]); 3.124 + glVertex3f(bmax[0], bmax[1], bmax[2]); 3.125 + glVertex3f(bmin[0], bmax[1], bmax[2]); 3.126 + glEnd(); 3.127 + glBegin(GL_LINE_LOOP); 3.128 + glVertex3f(bmin[0], bmax[1], bmin[2]); 3.129 + glVertex3f(bmax[0], bmax[1], bmin[2]); 3.130 + glVertex3f(bmax[0], bmax[1], bmax[2]); 3.131 + glVertex3f(bmin[0], bmax[1], bmax[2]); 3.132 + glEnd(); 3.133 + glBegin(GL_LINE_LOOP); 3.134 + glVertex3f(bmin[0], bmin[1], bmin[2]); 3.135 + glVertex3f(bmax[0], bmin[1], bmin[2]); 3.136 + glVertex3f(bmax[0], bmin[1], bmax[2]); 3.137 + glVertex3f(bmin[0], bmin[1], bmax[2]); 3.138 + glEnd(); 3.139 + 3.140 + // foo 3.141 + glDisable(GL_DEPTH_TEST); 3.142 + glEnable(GL_BLEND); 3.143 + glBlendFunc(GL_ONE, GL_ONE); 3.144 + glLineWidth(2.0); 3.145 + glColor3f(0, 0, 1); 3.146 + 3.147 + glBegin(GL_LINES); 3.148 + for(int i=0; i<neck_seg_count; i++) { 3.149 + glVertex3f(neck_seg[i].p[0].x, neck_seg[i].p[0].y, neck_seg[i].p[0].z); 3.150 + glVertex3f(neck_seg[i].p[1].x, neck_seg[i].p[1].y, neck_seg[i].p[1].z); 3.151 + } 3.152 + glEnd(); 3.153 + glLineWidth(1); 3.154 + 3.155 + // done debug drawing 3.156 + glPopAttrib(); 3.157 + if(cur_sdr) glUseProgram(cur_sdr); 3.158 + } 3.159 +} 3.160 + 3.161 +void Dragon::flush_dynvbo() const 3.162 +{ 3.163 + if(!dyn_vidx) return; 3.164 + 3.165 + glBindBuffer(GL_ARRAY_BUFFER, dyn_vbo); 3.166 + glBufferSubData(GL_ARRAY_BUFFER, 0, dyn_vidx * sizeof(DynVertex), dyn_varr); 3.167 + 3.168 + glEnableClientState(GL_VERTEX_ARRAY); 3.169 + glVertexPointer(3, GL_FLOAT, sizeof(DynVertex), (void*)offsetof(DynVertex, x)); 3.170 + glEnableClientState(GL_NORMAL_ARRAY); 3.171 + glNormalPointer(GL_FLOAT, sizeof(DynVertex), (void*)offsetof(DynVertex, nx)); 3.172 + glBindBuffer(GL_ARRAY_BUFFER, 0); 3.173 + 3.174 + glDrawArrays(GL_TRIANGLES, 0, dyn_vidx); 3.175 + 3.176 + glDisableClientState(GL_VERTEX_ARRAY); 3.177 + glDisableClientState(GL_NORMAL_ARRAY); 3.178 + dyn_vidx = 0; 3.179 +} 3.180 + 3.181 + 3.182 static Vector3 bezier(const Vector3 &a, const Vector3 &b, const Vector3 &c, const Vector3 &d, float t) 3.183 { 3.184 float x = bezier(a.x, b.x, c.x, d.x, t); 3.185 @@ -81,40 +238,48 @@ 3.186 return Vector3(x, y, z); 3.187 } 3.188 3.189 -void Dragon::draw() const 3.190 +static float mseval(struct metasurface *ms, float x, float y, float z) 3.191 { 3.192 - Vector3 bdir = breath_dir(); 3.193 - Vector3 bezcp[] = { pos, pos + dir * 6.0, head_pos - bdir * 8.0, head_pos }; 3.194 + Dragon *dragon = (Dragon*)msurf_get_user_data(ms); 3.195 3.196 - int cur_sdr; 3.197 - glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr); 3.198 - glUseProgram(0); 3.199 + Vector3 pt = Vector3(x, y, z); 3.200 + Capsule *seg = dragon->neck_seg; 3.201 3.202 - glPushAttrib(GL_ENABLE_BIT); 3.203 - glDisable(GL_LIGHTING); 3.204 + //printf("eval(%g %g %g)\n", x, y, z); 3.205 3.206 - glLineWidth(2.0); 3.207 - glColor3f(0, 0, 1); 3.208 + float sum = 0.0f; 3.209 + for(int i=0; i<dragon->neck_seg_count; i++) { 3.210 + float dist = capsule_distance(seg[i].p[0], seg[i].w[0], seg[i].p[1], seg[i].w[1], pt); 3.211 + //float dist = sphere_distance(seg[i].p[0], 1.0, pt); 3.212 + if(dist < 1e-4) dist = 1e-4; 3.213 + float energy = 0.0001 / (dist * dist); 3.214 + /*float dx = x - seg[i].p[0].x; 3.215 + float dy = y - seg[i].p[0].y; 3.216 + float dz = z - seg[i].p[0].z; 3.217 + float energy = 0.5 / (dx * dx + dy * dy + dz * dz);*/ 3.218 + sum += energy; 3.219 + } 3.220 + return sum; 3.221 +} 3.222 3.223 - glBegin(GL_LINE_STRIP); 3.224 - for(int i=0; i<10; i++) { 3.225 - float t = (float)i / 10.0f; 3.226 - Vector3 p = bezier(bezcp[0], bezcp[1], bezcp[2], bezcp[3], t); 3.227 - glVertex3f(p.x, p.y, p.z); 3.228 +static void msvertex(struct metasurface *ms, float x, float y, float z) 3.229 +{ 3.230 + Dragon *dragon = (Dragon*)msurf_get_user_data(ms); 3.231 + 3.232 + const float dt = 0.001; 3.233 + float dfdx = mseval(ms, x - dt, y, z) - mseval(ms, x + dt, y, z); 3.234 + float dfdy = mseval(ms, x, y - dt, z) - mseval(ms, x, y + dt, z); 3.235 + float dfdz = mseval(ms, x, y, z - dt) - mseval(ms, x, y, z + dt); 3.236 + 3.237 + DynVertex *vptr = dragon->dyn_varr + dragon->dyn_vidx++; 3.238 + vptr->x = x; 3.239 + vptr->y = y; 3.240 + vptr->z = z; 3.241 + vptr->nx = dfdx; 3.242 + vptr->ny = dfdy; 3.243 + vptr->nz = dfdz; 3.244 + 3.245 + if(dragon->dyn_vidx >= DYN_VCOUNT) { 3.246 + dragon->flush_dynvbo(); 3.247 } 3.248 - glEnd(); 3.249 - glLineWidth(1); 3.250 - 3.251 - glPointSize(5.0); 3.252 - glColor3f(0, 1, 0); 3.253 - 3.254 - glBegin(GL_POINTS); 3.255 - for(int i=0; i<4; i++) { 3.256 - glVertex3f(bezcp[i].x, bezcp[i].y, bezcp[i].z); 3.257 - } 3.258 - glEnd(); 3.259 - 3.260 - glPopAttrib(); 3.261 - 3.262 - glUseProgram(cur_sdr); 3.263 }
4.1 --- a/src/dragon.h Sun Aug 23 05:37:09 2015 +0300 4.2 +++ b/src/dragon.h Tue Aug 25 00:38:00 2015 +0300 4.3 @@ -2,6 +2,18 @@ 4.4 #define DRAGON_H_ 4.5 4.6 #include "vmath/vmath.h" 4.7 +#include "mesh.h" 4.8 +#include "metasurf.h" 4.9 + 4.10 +struct Capsule { 4.11 + Vector3 p[2]; 4.12 + float w[2]; 4.13 +}; 4.14 + 4.15 +struct DynVertex { 4.16 + float x, y, z; 4.17 + float nx, ny, nz; 4.18 +}; 4.19 4.20 class Dragon { 4.21 private: 4.22 @@ -9,6 +21,8 @@ 4.23 Vector3 head_pos, target; 4.24 float head_xlim[2], head_ylim[2]; 4.25 4.26 + struct metasurface *msurf; 4.27 + 4.28 public: 4.29 Dragon(); 4.30 ~Dragon(); 4.31 @@ -25,6 +39,15 @@ 4.32 4.33 void update(); 4.34 void draw() const; 4.35 + 4.36 + // implementation details, must be public for the msurf callbacks 4.37 + Capsule *neck_seg; 4.38 + int neck_seg_count; 4.39 + DynVertex *dyn_varr; 4.40 + mutable int dyn_vidx; 4.41 + unsigned int dyn_vbo; 4.42 + 4.43 + void flush_dynvbo() const; 4.44 }; 4.45 4.46 #endif // DRAGON_H_
5.1 --- a/src/game.cc Sun Aug 23 05:37:09 2015 +0300 5.2 +++ b/src/game.cc Tue Aug 25 00:38:00 2015 +0300 5.3 @@ -29,7 +29,7 @@ 5.4 static unsigned int modkeys; 5.5 5.6 5.7 -static Dragon dragon; 5.8 +static Dragon *dragon; 5.9 5.10 5.11 bool game_init() 5.12 @@ -71,11 +71,12 @@ 5.13 return false; 5.14 } 5.15 5.16 - dragon.set_position(Vector3(0, 5, 20)); 5.17 - dragon.set_direction(Vector3(0, 0, -1)); 5.18 - dragon.set_target(Vector3(0, 3, 0)); 5.19 - dragon.move_head(Vector3(0, 6, 10)); 5.20 - dragon.set_head_limits(-ROOM_WIDTH * 0.2, ROOM_WIDTH * 0.2, 1, ROOM_HEIGHT - 3); 5.21 + dragon = new Dragon; 5.22 + dragon->set_position(Vector3(0, 5, 20)); 5.23 + dragon->set_direction(Vector3(0, 0, -1)); 5.24 + dragon->set_target(Vector3(0, 3, 0)); 5.25 + dragon->move_head(Vector3(0, 6, 10)); 5.26 + dragon->set_head_limits(-ROOM_WIDTH * 0.2, ROOM_WIDTH * 0.2, 1, ROOM_HEIGHT - 3); 5.27 5.28 Mesh::use_custom_sdr_attr = false; 5.29 5.30 @@ -85,6 +86,7 @@ 5.31 5.32 void game_cleanup() 5.33 { 5.34 + delete dragon; 5.35 cleanup_room(); 5.36 } 5.37 5.38 @@ -92,7 +94,7 @@ 5.39 { 5.40 cur_time = time_msec; 5.41 5.42 - dragon.update(); 5.43 + dragon->update(); 5.44 } 5.45 5.46 void game_display() 5.47 @@ -158,7 +160,7 @@ 5.48 5.49 glPopMatrix(); 5.50 5.51 - dragon.draw(); 5.52 + dragon->draw(); 5.53 } 5.54 5.55 5.56 @@ -231,7 +233,7 @@ 5.57 prev_y = y; 5.58 5.59 if(gamectl) { 5.60 - dragon.move_head(dx * 0.1, -dy * 0.1); 5.61 + dragon->move_head(dx * 0.1, -dy * 0.1); 5.62 } 5.63 5.64 if(modkeys) {
6.1 --- a/src/geom.cc Sun Aug 23 05:37:09 2015 +0300 6.2 +++ b/src/geom.cc Tue Aug 25 00:38:00 2015 +0300 6.3 @@ -1,5 +1,6 @@ 6.4 +#include <assert.h> 6.5 +#include <float.h> 6.6 #include <algorithm> 6.7 -#include <float.h> 6.8 #include "geom.h" 6.9 6.10 GeomObject::~GeomObject() 6.11 @@ -249,3 +250,57 @@ 6.12 } 6.13 return true; 6.14 } 6.15 + 6.16 +float sphere_distance(const Vector3 ¢, float rad, const Vector3 &pt) 6.17 +{ 6.18 + return (pt - cent).length() - rad; 6.19 +} 6.20 + 6.21 +float capsule_distance(const Vector3 &a, float ra, const Vector3 &b, float rb, const Vector3 &pt) 6.22 +{ 6.23 + Vector3 ab_dir = b - a; 6.24 + 6.25 + if(fabs(ab_dir.length_sq()) < 1e-5) { 6.26 + // if a == b, the capsule is a sphere with radius the maximum of the capsule radii 6.27 + return sphere_distance(a, std::max(ra, rb), pt); 6.28 + } 6.29 + float ab_len = ab_dir.length(); 6.30 + 6.31 + Vector3 ap_dir = pt - a; 6.32 + Vector3 rotaxis = cross_product(ab_dir, ap_dir).normalized(); 6.33 + 6.34 + Matrix4x4 rmat; 6.35 + rmat.set_rotation(rotaxis, M_PI / 2.0); 6.36 + Vector3 right = ab_dir.transformed(rmat) / ab_len; 6.37 + 6.38 + // XXX I think this check is redundant, always false, due to the cross product order 6.39 + //assert(dot_product(right, ab_dir) >= 0.0); 6.40 + if(dot_product(right, ab_dir) < 0.0) { 6.41 + right = -right; 6.42 + } 6.43 + Vector3 aa = a + right * ra; 6.44 + Vector3 bb = b + right * rb; 6.45 + 6.46 + // project pt to the line segment bb-aa, see if the projection lies within the interval [0, 1) 6.47 + Vector3 aabb_dir = bb - aa; 6.48 + float aabb_len = aabb_dir.length(); 6.49 + Vector3 aap_dir = pt - aa; 6.50 + 6.51 + float t = dot_product(aap_dir, aabb_dir / aabb_len) / aabb_len; 6.52 + if(t < 0.0) { 6.53 + return sphere_distance(a, ra, pt); 6.54 + } 6.55 + if(t >= 1.0) { 6.56 + return sphere_distance(b, rb, pt); 6.57 + } 6.58 + 6.59 + Vector3 ppt = aa + aabb_dir * t; 6.60 + Vector3 norm = ppt - pt; 6.61 + float dist = norm.length(); 6.62 + 6.63 + if(dot_product(norm, right) < 0.0) { 6.64 + // inside the cone 6.65 + dist = -dist; 6.66 + } 6.67 + return dist; 6.68 +}
7.1 --- a/src/geom.h Sun Aug 23 05:37:09 2015 +0300 7.2 +++ b/src/geom.h Tue Aug 25 00:38:00 2015 +0300 7.3 @@ -67,4 +67,7 @@ 7.4 bool intersect(const Ray &ray, HitPoint *hit = 0) const; 7.5 }; 7.6 7.7 +float sphere_distance(const Vector3 ¢, float rad, const Vector3 &pt); 7.8 +float capsule_distance(const Vector3 &a, float ra, const Vector3 &b, float rb, const Vector3 &pt); 7.9 + 7.10 #endif // GEOMOBJ_H_