rayzor

annotate src/object.cc @ 17:79609d482762

the renderer renders, also fixed an unnoticed matrix conversion problem between scenegraph and min3d
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 14 Apr 2014 07:34:45 +0300
parents a9a948809c6f
children
rev   line source
nuclear@14 1 #include <math.h>
nuclear@1 2 #include "object.h"
nuclear@1 3 #include "vmath.h"
nuclear@1 4 #include "min3d.h"
nuclear@9 5 #include "logger.h"
nuclear@1 6
nuclear@1 7 Object::Object()
nuclear@1 8 {
nuclear@12 9 type = NODE_OBJECT;
nuclear@1 10 }
nuclear@1 11
nuclear@1 12 Object::~Object()
nuclear@1 13 {
nuclear@1 14 }
nuclear@1 15
nuclear@17 16 Vector3 Object::hit_normal(const RayHit &hit) const
nuclear@17 17 {
nuclear@17 18 return Vector3(0, 0, 0);
nuclear@17 19 }
nuclear@17 20
nuclear@1 21 // ---- sphere ----
nuclear@1 22 Sphere::Sphere()
nuclear@1 23 {
nuclear@1 24 }
nuclear@1 25
nuclear@1 26 Sphere::~Sphere()
nuclear@1 27 {
nuclear@1 28 }
nuclear@1 29
nuclear@9 30 #define USUB 12
nuclear@9 31 #define VSUB 6
nuclear@1 32
nuclear@14 33 void Sphere::draw(bool emph) const
nuclear@1 34 {
nuclear@1 35 static Vector3 *varr;
nuclear@9 36 static unsigned int *iarr;
nuclear@9 37 static int num_verts, num_indices;
nuclear@1 38 if(!varr) {
nuclear@9 39 int i, j;
nuclear@1 40 int uverts = USUB;
nuclear@1 41 int vverts = VSUB + 1;
nuclear@9 42
nuclear@1 43 num_verts = uverts * vverts;
nuclear@1 44 varr = new Vector3[num_verts];
nuclear@1 45
nuclear@1 46 Vector3 *vptr = varr;
nuclear@9 47 for(i=0; i<vverts; i++) {
nuclear@9 48 float v = (float)i / (float)VSUB;
nuclear@9 49 float phi = v * M_PI;
nuclear@9 50 for(j=0; j<uverts; j++) {
nuclear@9 51 float u = (float)j / (float)uverts;
nuclear@9 52 float theta = u * M_PI * 2.0;
nuclear@1 53
nuclear@9 54 float x = sin(theta) * sin(phi);
nuclear@12 55 float y = -cos(phi);
nuclear@9 56 float z = cos(theta) * sin(phi);
nuclear@1 57
nuclear@1 58 *vptr++ = Vector3(x, y, z);
nuclear@1 59 }
nuclear@1 60 }
nuclear@9 61
nuclear@9 62 num_indices = USUB * VSUB * 4;
nuclear@9 63 iarr = new unsigned int[num_indices];
nuclear@9 64
nuclear@9 65 unsigned int *iptr = iarr;
nuclear@9 66 for(i=0; i<VSUB; i++) {
nuclear@9 67 for(j=0; j<USUB; j++) {
nuclear@9 68 iptr[0] = i * uverts + j;
nuclear@9 69 iptr[1] = i * uverts + ((j + 1) % uverts);
nuclear@9 70 iptr[2] = iptr[1] + uverts;
nuclear@9 71 iptr[3] = iptr[0] + uverts;
nuclear@9 72 iptr += 4;
nuclear@9 73 }
nuclear@9 74 }
nuclear@9 75
nuclear@9 76 printlog("created sphere mesh\n");
nuclear@9 77 printlog(" vertices: %d (%d slices, %d stacks)\n", num_verts, uverts, vverts);
nuclear@9 78 printlog(" quads: %d (%d indices, %d usub, %d vsub)\n", USUB * VSUB, num_indices, USUB, VSUB);
nuclear@1 79 }
nuclear@1 80
nuclear@12 81 pre_draw();
nuclear@14 82 SceneNode::draw(emph);
nuclear@9 83
nuclear@5 84 m3d_vertex_array(&varr->x);
nuclear@9 85 m3d_draw_indexed(M3D_QUADS, iarr, num_indices);
nuclear@5 86 m3d_vertex_array(0);
nuclear@12 87
nuclear@12 88 post_draw();
nuclear@1 89 }
nuclear@12 90
nuclear@17 91 bool Sphere::intersect(const Ray &wray, RayHit *hit) const
nuclear@12 92 {
nuclear@14 93 Ray ray = transform(get_inv_matrix(), wray);
nuclear@14 94
nuclear@14 95 // assumes center is 0,0,0, and radius is 1
nuclear@14 96 float a = dot(ray.dir, ray.dir);
nuclear@14 97 float b = 2.0 * ray.dir.x * ray.origin.x +
nuclear@14 98 2.0 * ray.dir.y * ray.origin.y +
nuclear@14 99 2.0 * ray.dir.z * ray.origin.z;
nuclear@14 100 float c = dot(ray.origin, ray.origin) - 1.0;
nuclear@14 101
nuclear@14 102 float discr = b * b - 4.0 * a * c;
nuclear@14 103 if(discr < 1e-4)
nuclear@14 104 return false;
nuclear@14 105
nuclear@14 106 float sqrt_discr = sqrt(discr);
nuclear@14 107 float t0 = (-b + sqrt_discr) / (2.0 * a);
nuclear@14 108 float t1 = (-b - sqrt_discr) / (2.0 * a);
nuclear@14 109
nuclear@14 110 if(t0 < 1e-4)
nuclear@14 111 t0 = t1;
nuclear@14 112 if(t1 < 1e-4)
nuclear@14 113 t1 = t0;
nuclear@14 114
nuclear@14 115 float t = t0 < t1 ? t0 : t1;
nuclear@14 116 if(t < 1e-4)
nuclear@14 117 return false;
nuclear@14 118
nuclear@17 119 if(hit) {
nuclear@17 120 hit->ray = wray;
nuclear@17 121 hit->lray = ray;
nuclear@17 122 hit->dist = t;
nuclear@17 123 hit->obj = this;
nuclear@17 124 hit->subobj = 0;
nuclear@17 125 }
nuclear@14 126 return true;
nuclear@12 127 }
nuclear@12 128
nuclear@17 129 Vector3 Sphere::hit_normal(const RayHit &hit) const
nuclear@17 130 {
nuclear@17 131 return hit.lray.origin + hit.lray.dir * hit.dist;
nuclear@17 132 }
nuclear@17 133
nuclear@12 134 // ---- box ----
nuclear@12 135
nuclear@12 136 Box::Box()
nuclear@12 137 {
nuclear@12 138 }
nuclear@12 139
nuclear@12 140 Box::~Box()
nuclear@12 141 {
nuclear@12 142 }
nuclear@12 143
nuclear@12 144 /*
nuclear@12 145 3--------2
nuclear@12 146 /. .\
nuclear@12 147 0------------1
nuclear@12 148 | 7--------6 |
nuclear@12 149 |/ \|
nuclear@12 150 4------------5
nuclear@12 151
nuclear@12 152 */
nuclear@14 153 void Box::draw(bool emph) const
nuclear@12 154 {
nuclear@12 155 static const float verts[] = {
nuclear@12 156 -1, 1, 1,
nuclear@12 157 1, 1, 1,
nuclear@12 158 1, 1, -1,
nuclear@12 159 -1, 1, -1,
nuclear@12 160 -1, -1, 1,
nuclear@12 161 1, -1, 1,
nuclear@12 162 1, -1, -1,
nuclear@12 163 -1, -1, -1
nuclear@12 164 };
nuclear@12 165 static const unsigned int indices[] = {
nuclear@12 166 0, 1, 2, 3, // top
nuclear@12 167 4, 7, 6, 5, // bottom
nuclear@12 168 0, 4, 5, 1, // front
nuclear@12 169 5, 6, 2, 1, // right
nuclear@12 170 6, 7, 3, 2, // back
nuclear@12 171 7, 4, 0, 3 // left
nuclear@12 172 };
nuclear@12 173
nuclear@12 174 pre_draw();
nuclear@14 175 SceneNode::draw(emph);
nuclear@12 176
nuclear@12 177 m3d_vertex_array(verts);
nuclear@12 178 m3d_draw_indexed(M3D_QUADS, indices, sizeof indices / sizeof *indices);
nuclear@12 179 m3d_vertex_array(0);
nuclear@12 180
nuclear@12 181 post_draw();
nuclear@12 182 }
nuclear@12 183
nuclear@17 184 bool Box::intersect(const Ray &wray, RayHit *hit) const
nuclear@12 185 {
nuclear@17 186 Ray ray = transform(get_inv_matrix(), wray);
nuclear@17 187
nuclear@17 188 Vector3 param[2] = { Vector3(-1, -1, -1), Vector3(1, 1, 1) };
nuclear@17 189 Vector3 inv_dir(1.0 / ray.dir.x, 1.0 / ray.dir.y, 1.0 / ray.dir.z);
nuclear@17 190 int sign[3] = {inv_dir.x < 0, inv_dir.y < 0, inv_dir.z < 0};
nuclear@17 191
nuclear@17 192 float tmin = (param[sign[0]].x - ray.origin.x) * inv_dir.x;
nuclear@17 193 float tmax = (param[1 - sign[0]].x - ray.origin.x) * inv_dir.x;
nuclear@17 194 float tymin = (param[sign[1]].y - ray.origin.y) * inv_dir.y;
nuclear@17 195 float tymax = (param[1 - sign[1]].y - ray.origin.y) * inv_dir.y;
nuclear@17 196
nuclear@17 197 if(tmin > tymax || tymin > tmax) {
nuclear@17 198 return false;
nuclear@17 199 }
nuclear@17 200 if(tymin > tmin) tmin = tymin;
nuclear@17 201 if(tymax < tmax) tmax = tymax;
nuclear@17 202
nuclear@17 203 float tzmin = (param[sign[2]].z - ray.origin.z) * inv_dir.z;
nuclear@17 204 float tzmax = (param[1 - sign[2]].z - ray.origin.z) * inv_dir.z;
nuclear@17 205
nuclear@17 206 if(tmin > tzmax || tzmin > tmax) {
nuclear@17 207 return false;
nuclear@17 208 }
nuclear@17 209 if(tzmin > tmin) tmin = tzmin;
nuclear@17 210 if(tzmax < tmax) tmax = tzmax;
nuclear@17 211
nuclear@17 212 float t = tmin < 1e-4 ? tmax : tmin;
nuclear@17 213 if(t >= 1e-4) {
nuclear@17 214 if(hit) {
nuclear@17 215 hit->dist = t;
nuclear@17 216 hit->ray = wray;
nuclear@17 217 hit->lray = ray;
nuclear@17 218 hit->obj = this;
nuclear@17 219 hit->subobj = 0;
nuclear@17 220 }
nuclear@17 221 return true;
nuclear@17 222 }
nuclear@17 223 return false;
nuclear@12 224 }
nuclear@17 225
nuclear@17 226 Vector3 Box::hit_normal(const RayHit &hit) const
nuclear@17 227 {
nuclear@17 228 Vector3 lpt = hit.lray.origin + hit.lray.dir * hit.dist;
nuclear@17 229
nuclear@17 230 if(fabs(lpt.x) > fabs(lpt.y) && fabs(lpt.x) > fabs(lpt.z)) {
nuclear@17 231 return Vector3(lpt.x, 0, 0);
nuclear@17 232 }
nuclear@17 233 if(fabs(lpt.y) > fabs(lpt.z)) {
nuclear@17 234 return Vector3(0, lpt.y, 0);
nuclear@17 235 }
nuclear@17 236 return Vector3(0, 0, lpt.z);
nuclear@17 237 }