[2197] | 1 | #include "dxstdafx.h" |
---|
| 2 | #include "Triangle.hpp" |
---|
| 3 | |
---|
| 4 | Triangle::Triangle(const Vector* a, const Vector* b, const Vector* c, const Material* material) |
---|
| 5 | :a(a),b(b),c(c) |
---|
| 6 | { |
---|
| 7 | this->material = material; |
---|
| 8 | // calculate normals |
---|
| 9 | normal = ((*a) - (*b)) && ((*a) - (*c)); |
---|
| 10 | normal.normalize(); |
---|
| 11 | |
---|
| 12 | // pre-calculate values for intersection tests |
---|
| 13 | float x = fabsf (normal.x); |
---|
| 14 | float y = fabsf (normal.y); |
---|
| 15 | float z = fabsf (normal.z); |
---|
| 16 | dominantAxis = (x > y) ? ((x > z) ? X_DOMINANT : Z_DOMINANT) : ((y > z) ? Y_DOMINANT : Z_DOMINANT); |
---|
| 17 | |
---|
| 18 | hyperPlaneShiftOffset = normal * (*a); |
---|
| 19 | |
---|
| 20 | switch (dominantAxis) { |
---|
| 21 | case X_DOMINANT: |
---|
| 22 | d1 = b->z - a->z; |
---|
| 23 | d2 = b->y - a->y; |
---|
| 24 | d3 = c->z - b->z; |
---|
| 25 | d4 = c->y - b->y; |
---|
| 26 | d5 = a->z - c->z; |
---|
| 27 | d6 = a->y - c->y; |
---|
| 28 | break; |
---|
| 29 | case Y_DOMINANT: |
---|
| 30 | d1 = b->z - a->z; |
---|
| 31 | d2 = b->x - a->x; |
---|
| 32 | d3 = c->z - b->z; |
---|
| 33 | d4 = c->x - b->x; |
---|
| 34 | d5 = a->z - c->z; |
---|
| 35 | d6 = a->x - c->x; |
---|
| 36 | break; |
---|
| 37 | case Z_DOMINANT: |
---|
| 38 | d1 = b->y - a->y; |
---|
| 39 | d2 = b->x - a->x; |
---|
| 40 | d3 = c->y - b->y; |
---|
| 41 | d4 = c->x - b->x; |
---|
| 42 | d5 = a->y - c->y; |
---|
| 43 | d6 = a->x - c->x; |
---|
| 44 | break; |
---|
| 45 | } |
---|
| 46 | |
---|
| 47 | bbox.minPoint = *a; |
---|
| 48 | bbox.minPoint <= *b; |
---|
| 49 | bbox.minPoint <= *c; |
---|
| 50 | |
---|
| 51 | bbox.maxPoint = *a; |
---|
| 52 | bbox.maxPoint >= *b; |
---|
| 53 | bbox.maxPoint >= *c; |
---|
| 54 | } |
---|
| 55 | |
---|
| 56 | bool Triangle::intersect (const Ray& ray, float& depth, float rayMin, float rayMax) |
---|
| 57 | { |
---|
| 58 | lastTestedRayId = ray.id; |
---|
| 59 | lastTestedRayResult.isIntersect = false; |
---|
| 60 | |
---|
| 61 | float cosa = normal * ray.dir; |
---|
| 62 | if (cosa > -0.00001f) // back facing triangle |
---|
| 63 | return false; |
---|
| 64 | |
---|
| 65 | float originDistOnNormal = -(normal * ray.origin); |
---|
| 66 | depth = (hyperPlaneShiftOffset + originDistOnNormal) / cosa; |
---|
| 67 | if (depth < 0.0f) |
---|
| 68 | return false; |
---|
| 69 | |
---|
| 70 | float s, t; |
---|
| 71 | switch (dominantAxis) |
---|
| 72 | { |
---|
| 73 | case X_DOMINANT: |
---|
| 74 | // project to YZ plane than |
---|
| 75 | // test that tg (P2->P1) > tg (P2->pintersect), |
---|
| 76 | // so if pintersect is on the wrong side, drop it |
---|
| 77 | s = ray.origin.y + depth * ray.dir.y; |
---|
| 78 | t = ray.origin.z + depth * ray.dir.z; |
---|
| 79 | |
---|
| 80 | if ((b->y - s) * (d1) < (b->z - t) * (d2)) // speed up: e->g store: (b->z - a->z) |
---|
| 81 | return false; |
---|
| 82 | if ((c->y - s) * (d3) < (c->z - t) * (d4)) |
---|
| 83 | return false; |
---|
| 84 | if ((a->y - s) * (d5) < (a->z - t) * (d6)) |
---|
| 85 | return false; |
---|
| 86 | |
---|
| 87 | lastTestedRayResult.isIntersect = true; |
---|
| 88 | lastTestedRayResult.material = this->material; |
---|
| 89 | lastTestedRayResult.normal = this->normal; |
---|
| 90 | lastTestedRayResult.depth = depth; |
---|
| 91 | lastTestedRayResult.point = ray.origin + ray.dir * depth; |
---|
| 92 | lastTestedRayResult.object = this; |
---|
| 93 | return true; |
---|
| 94 | |
---|
| 95 | case Y_DOMINANT: |
---|
| 96 | s = ray.origin.x + depth * ray.dir.x; |
---|
| 97 | t = ray.origin.z + depth * ray.dir.z; |
---|
| 98 | |
---|
| 99 | if ((b->x - s) * (d1) < (b->z - t) * (d2)) |
---|
| 100 | return false; |
---|
| 101 | if ((c->x - s) * (d3) < (c->z - t) * (d4)) |
---|
| 102 | return false; |
---|
| 103 | if ((a->x - s) * (d5) < (a->z - t) * (d6)) |
---|
| 104 | return false; |
---|
| 105 | lastTestedRayResult.isIntersect = true; |
---|
| 106 | lastTestedRayResult.material = this->material; |
---|
| 107 | lastTestedRayResult.normal = this->normal; |
---|
| 108 | lastTestedRayResult.depth = depth; |
---|
| 109 | lastTestedRayResult.point = ray.origin + ray.dir * depth; |
---|
| 110 | lastTestedRayResult.object = this; |
---|
| 111 | return true; |
---|
| 112 | |
---|
| 113 | case Z_DOMINANT: |
---|
| 114 | s = ray.origin.x + depth * ray.dir.x; |
---|
| 115 | t = ray.origin.y + depth * ray.dir.y; |
---|
| 116 | |
---|
| 117 | if ((b->x - s) * (d1) < (b->y - t) * (d2)) |
---|
| 118 | return false; |
---|
| 119 | if ((c->x - s) * (d3) < (c->y - t) * (d4)) |
---|
| 120 | return false; |
---|
| 121 | if ((a->x - s) * (d5) < (a->y - t) * (d6)) |
---|
| 122 | return false; |
---|
| 123 | lastTestedRayResult.isIntersect = true; |
---|
| 124 | lastTestedRayResult.material = this->material; |
---|
| 125 | lastTestedRayResult.normal = this->normal; |
---|
| 126 | lastTestedRayResult.depth = depth; |
---|
| 127 | lastTestedRayResult.point = ray.origin + ray.dir * depth; |
---|
| 128 | lastTestedRayResult.object = this; |
---|
| 129 | return true; |
---|
| 130 | } |
---|
| 131 | return false; |
---|
| 132 | } |
---|
| 133 | |
---|
| 134 | bool Triangle::intersectBackSide (const Ray& ray, float& depth, float rayMin, float rayMax) |
---|
| 135 | { |
---|
| 136 | lastTestedRayId = ray.id; |
---|
| 137 | lastTestedRayResult.isIntersect = false; |
---|
| 138 | |
---|
| 139 | float cosa = normal * ray.dir; |
---|
| 140 | if (cosa < 0.00001f) // front facing triangle |
---|
| 141 | return false; |
---|
| 142 | |
---|
| 143 | float originDistOnNormal = normal * ray.origin; |
---|
| 144 | depth = -(hyperPlaneShiftOffset + originDistOnNormal) / cosa; |
---|
| 145 | if (depth < 0.0f) |
---|
| 146 | return false; |
---|
| 147 | |
---|
| 148 | float s, t; |
---|
| 149 | switch (dominantAxis) |
---|
| 150 | { |
---|
| 151 | case X_DOMINANT: |
---|
| 152 | // project to YZ plane than |
---|
| 153 | // test that tg (P2->P1) > tg (P2->pintersect), |
---|
| 154 | // so if pintersect is on the wrong side, drop it |
---|
| 155 | s = ray.origin.y + depth * ray.dir.y; |
---|
| 156 | t = ray.origin.z + depth * ray.dir.z; |
---|
| 157 | |
---|
| 158 | if ((b->y - s) * (d1) < (b->z - t) * (d2)) // speed up: e->g store: (b->z - a->z) |
---|
| 159 | return false; |
---|
| 160 | if ((c->y - s) * (d3) < (c->z - t) * (d4)) |
---|
| 161 | return false; |
---|
| 162 | if ((a->y - s) * (d5) < (a->z - t) * (d6)) |
---|
| 163 | return false; |
---|
| 164 | |
---|
| 165 | lastTestedRayResult.isIntersect = true; |
---|
| 166 | lastTestedRayResult.material = this->material; |
---|
| 167 | lastTestedRayResult.normal = this->normal; |
---|
| 168 | lastTestedRayResult.depth = depth; |
---|
| 169 | lastTestedRayResult.point = ray.origin + ray.dir * depth; |
---|
| 170 | lastTestedRayResult.object = this; |
---|
| 171 | return true; |
---|
| 172 | |
---|
| 173 | case Y_DOMINANT: |
---|
| 174 | s = ray.origin.x + depth * ray.dir.x; |
---|
| 175 | t = ray.origin.z + depth * ray.dir.z; |
---|
| 176 | |
---|
| 177 | if ((b->x - s) * (d1) < (b->z - t) * (d2)) |
---|
| 178 | return false; |
---|
| 179 | if ((c->x - s) * (d3) < (c->z - t) * (d4)) |
---|
| 180 | return false; |
---|
| 181 | if ((a->x -s) * (d5) < (a->z - t) * (d6)) |
---|
| 182 | return false; |
---|
| 183 | lastTestedRayResult.isIntersect = true; |
---|
| 184 | lastTestedRayResult.material = this->material; |
---|
| 185 | lastTestedRayResult.normal = this->normal; |
---|
| 186 | lastTestedRayResult.depth = depth; |
---|
| 187 | lastTestedRayResult.point = ray.origin + ray.dir * depth; |
---|
| 188 | lastTestedRayResult.object = this; |
---|
| 189 | return true; |
---|
| 190 | |
---|
| 191 | case Z_DOMINANT: |
---|
| 192 | s = ray.origin.x + depth * ray.dir.x; |
---|
| 193 | t = ray.origin.y + depth * ray.dir.y; |
---|
| 194 | |
---|
| 195 | if ((b->x - s) * (d1) < (b->y - t) * (d2)) |
---|
| 196 | return false; |
---|
| 197 | if ((c->x - s) * (d3) < (c->y - t) * (d4)) |
---|
| 198 | return false; |
---|
| 199 | if ((a->x - s) * (d5) < (a->y - t) * (d6)) |
---|
| 200 | return false; |
---|
| 201 | lastTestedRayResult.isIntersect = true; |
---|
| 202 | lastTestedRayResult.material = this->material; |
---|
| 203 | lastTestedRayResult.normal = this->normal; |
---|
| 204 | lastTestedRayResult.depth = depth; |
---|
| 205 | lastTestedRayResult.point = ray.origin + ray.dir * depth; |
---|
| 206 | lastTestedRayResult.object = this; |
---|
| 207 | return true; |
---|
| 208 | } |
---|
| 209 | return false; |
---|
| 210 | } |
---|