Showing the changes to interface/src/MetavoxelSystem.cpp (1 of 6 files). Show all
Unified · Split
| @@ -171,185 +171,6 @@ void MetavoxelSystem::refreshVoxelData() { · 170 unmodified lines | |||
| 171 | } | 171 | } |
| 172 | } | 172 | } |
| 173 | 173 | ||
| 174 | class RayHeightfieldIntersectionVisitor : public RayIntersectionVisitor { | ||
| 175 | public: | ||
| 176 | |||
| 177 | float intersectionDistance; | ||
| 178 | |||
| 179 | RayHeightfieldIntersectionVisitor(const glm::vec3& origin, const glm::vec3& direction, const MetavoxelLOD& lod); | ||
| 180 | |||
| 181 | virtual int visit(MetavoxelInfo& info, float distance); | ||
| 182 | }; | ||
| 183 | |||
| 184 | RayHeightfieldIntersectionVisitor::RayHeightfieldIntersectionVisitor(const glm::vec3& origin, | ||
| 185 | const glm::vec3& direction, const MetavoxelLOD& lod) : | ||
| 186 | RayIntersectionVisitor(origin, direction, QVector<AttributePointer>() << | ||
| 187 | Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), QVector<AttributePointer>(), lod), | ||
| 188 | intersectionDistance(FLT_MAX) { | ||
| 189 | } | ||
| 190 | |||
| 191 | static const int EIGHT_BIT_MAXIMUM = 255; | ||
| 192 | static const float EIGHT_BIT_MAXIMUM_RECIPROCAL = 1.0f / EIGHT_BIT_MAXIMUM; | ||
| 193 | |||
| 194 | int RayHeightfieldIntersectionVisitor::visit(MetavoxelInfo& info, float distance) { | ||
| 195 | if (!info.isLeaf) { | ||
| 196 | return _order; | ||
| 197 | } | ||
| 198 | const HeightfieldBuffer* buffer = static_cast<HeightfieldBuffer*>( | ||
| 199 | info.inputValues.at(0).getInlineValue<BufferDataPointer>().data()); | ||
| 200 | if (!buffer) { | ||
| 201 | return STOP_RECURSION; | ||
| 202 | } | ||
| 203 | const QByteArray& contents = buffer->getHeight(); | ||
| 204 | const uchar* src = (const uchar*)contents.constData(); | ||
| 205 | int size = glm::sqrt((float)contents.size()); | ||
| 206 | int unextendedSize = size - HeightfieldBuffer::HEIGHT_EXTENSION; | ||
| 207 | int highest = HeightfieldBuffer::HEIGHT_BORDER + unextendedSize; | ||
| 208 | float heightScale = unextendedSize * EIGHT_BIT_MAXIMUM_RECIPROCAL; | ||
| 209 | |||
| 210 | // find the initial location in heightfield coordinates | ||
| 211 | glm::vec3 entry = (_origin + distance * _direction - info.minimum) * (float)unextendedSize / info.size; | ||
| 212 | entry.x += HeightfieldBuffer::HEIGHT_BORDER; | ||
| 213 | entry.z += HeightfieldBuffer::HEIGHT_BORDER; | ||
| 214 | glm::vec3 floors = glm::floor(entry); | ||
| 215 | glm::vec3 ceils = glm::ceil(entry); | ||
| 216 | if (floors.x == ceils.x) { | ||
| 217 | if (_direction.x > 0.0f) { | ||
| 218 | ceils.x += 1.0f; | ||
| 219 | } else { | ||
| 220 | floors.x -= 1.0f; | ||
| 221 | } | ||
| 222 | } | ||
| 223 | if (floors.z == ceils.z) { | ||
| 224 | if (_direction.z > 0.0f) { | ||
| 225 | ceils.z += 1.0f; | ||
| 226 | } else { | ||
| 227 | floors.z -= 1.0f; | ||
| 228 | } | ||
| 229 | } | ||
| 230 | |||
| 231 | bool withinBounds = true; | ||
| 232 | float accumulatedDistance = 0.0f; | ||
| 233 | while (withinBounds) { | ||
| 234 | // find the heights at the corners of the current cell | ||
| 235 | int floorX = qMin(qMax((int)floors.x, HeightfieldBuffer::HEIGHT_BORDER), highest); | ||
| 236 | int floorZ = qMin(qMax((int)floors.z, HeightfieldBuffer::HEIGHT_BORDER), highest); | ||
| 237 | int ceilX = qMin(qMax((int)ceils.x, HeightfieldBuffer::HEIGHT_BORDER), highest); | ||
| 238 | int ceilZ = qMin(qMax((int)ceils.z, HeightfieldBuffer::HEIGHT_BORDER), highest); | ||
| 239 | float upperLeft = src[floorZ * size + floorX] * heightScale; | ||
| 240 | float upperRight = src[floorZ * size + ceilX] * heightScale; | ||
| 241 | float lowerLeft = src[ceilZ * size + floorX] * heightScale; | ||
| 242 | float lowerRight = src[ceilZ * size + ceilX] * heightScale; | ||
| 243 | |||
| 244 | // find the distance to the next x coordinate | ||
| 245 | float xDistance = FLT_MAX; | ||
| 246 | if (_direction.x > 0.0f) { | ||
| 247 | xDistance = (ceils.x - entry.x) / _direction.x; | ||
| 248 | } else if (_direction.x < 0.0f) { | ||
| 249 | xDistance = (floors.x - entry.x) / _direction.x; | ||
| 250 | } | ||
| 251 | |||
| 252 | // and the distance to the next z coordinate | ||
| 253 | float zDistance = FLT_MAX; | ||
| 254 | if (_direction.z > 0.0f) { | ||
| 255 | zDistance = (ceils.z - entry.z) / _direction.z; | ||
| 256 | } else if (_direction.z < 0.0f) { | ||
| 257 | zDistance = (floors.z - entry.z) / _direction.z; | ||
| 258 | } | ||
| 259 | |||
| 260 | // the exit distance is the lower of those two | ||
| 261 | float exitDistance = qMin(xDistance, zDistance); | ||
| 262 | glm::vec3 exit, nextFloors = floors, nextCeils = ceils; | ||
| 263 | if (exitDistance == FLT_MAX) { | ||
| 264 | if (_direction.y > 0.0f) { | ||
| 265 | return SHORT_CIRCUIT; // line points upwards; no collisions possible | ||
| 266 | } | ||
| 267 | withinBounds = false; // line points downwards; check this cell only | ||
| 268 | |||
| 269 | } else { | ||
| 270 | // find the exit point and the next cell, and determine whether it's still within the bounds | ||
| 271 | exit = entry + exitDistance * _direction; | ||
| 272 | withinBounds = (exit.y >= HeightfieldBuffer::HEIGHT_BORDER && exit.y <= highest); | ||
| 273 | if (exitDistance == xDistance) { | ||
| 274 | if (_direction.x > 0.0f) { | ||
| 275 | nextFloors.x += 1.0f; | ||
| 276 | withinBounds &= (nextCeils.x += 1.0f) <= highest; | ||
| 277 | } else { | ||
| 278 | withinBounds &= (nextFloors.x -= 1.0f) >= HeightfieldBuffer::HEIGHT_BORDER; | ||
| 279 | nextCeils.x -= 1.0f; | ||
| 280 | } | ||
| 281 | } | ||
| 282 | if (exitDistance == zDistance) { | ||
| 283 | if (_direction.z > 0.0f) { | ||
| 284 | nextFloors.z += 1.0f; | ||
| 285 | withinBounds &= (nextCeils.z += 1.0f) <= highest; | ||
| 286 | } else { | ||
| 287 | withinBounds &= (nextFloors.z -= 1.0f) >= HeightfieldBuffer::HEIGHT_BORDER; | ||
| 288 | nextCeils.z -= 1.0f; | ||
| 289 | } | ||
| 290 | } | ||
| 291 | // check the vertical range of the ray against the ranges of the cell heights | ||
| 292 | if (qMin(entry.y, exit.y) > qMax(qMax(upperLeft, upperRight), qMax(lowerLeft, lowerRight)) || | ||
| 293 | qMax(entry.y, exit.y) < qMin(qMin(upperLeft, upperRight), qMin(lowerLeft, lowerRight))) { | ||
| 294 | entry = exit; | ||
| 295 | floors = nextFloors; | ||
| 296 | ceils = nextCeils; | ||
| 297 | accumulatedDistance += exitDistance; | ||
| 298 | continue; | ||
| 299 | } | ||
| 300 | } | ||
| 301 | // having passed the bounds check, we must check against the planes | ||
| 302 | glm::vec3 relativeEntry = entry - glm::vec3(floors.x, upperLeft, floors.z); | ||
| 303 | |||
| 304 | // first check the triangle including the Z+ segment | ||
| 305 | glm::vec3 lowerNormal(lowerLeft - lowerRight, 1.0f, upperLeft - lowerLeft); | ||
| 306 | float lowerProduct = glm::dot(lowerNormal, _direction); | ||
| 307 | if (lowerProduct < 0.0f) { | ||
| 308 | float planeDistance = -glm::dot(lowerNormal, relativeEntry) / lowerProduct; | ||
| 309 | glm::vec3 intersection = relativeEntry + planeDistance * _direction; | ||
| 310 | if (intersection.x >= 0.0f && intersection.x <= 1.0f && intersection.z >= 0.0f && intersection.z <= 1.0f && | ||
| 311 | intersection.z >= intersection.x) { | ||
| 312 | intersectionDistance = qMin(intersectionDistance, distance + | ||
| 313 | (accumulatedDistance + planeDistance) * (info.size / unextendedSize)); | ||
| 314 | return SHORT_CIRCUIT; | ||
| 315 | } | ||
| 316 | } | ||
| 317 | |||
| 318 | // then the one with the X+ segment | ||
| 319 | glm::vec3 upperNormal(upperLeft - upperRight, 1.0f, upperRight - lowerRight); | ||
| 320 | float upperProduct = glm::dot(upperNormal, _direction); | ||
| 321 | if (upperProduct < 0.0f) { | ||
| 322 | float planeDistance = -glm::dot(upperNormal, relativeEntry) / upperProduct; | ||
| 323 | glm::vec3 intersection = relativeEntry + planeDistance * _direction; | ||
| 324 | if (intersection.x >= 0.0f && intersection.x <= 1.0f && intersection.z >= 0.0f && intersection.z <= 1.0f && | ||
| 325 | intersection.x >= intersection.z) { | ||
| 326 | intersectionDistance = qMin(intersectionDistance, distance + | ||
| 327 | (accumulatedDistance + planeDistance) * (info.size / unextendedSize)); | ||
| 328 | return SHORT_CIRCUIT; | ||
| 329 | } | ||
| 330 | } | ||
| 331 | |||
| 332 | // no joy; continue on our way | ||
| 333 | entry = exit; | ||
| 334 | floors = nextFloors; | ||
| 335 | ceils = nextCeils; | ||
| 336 | accumulatedDistance += exitDistance; | ||
| 337 | } | ||
| 338 | |||
| 339 | return STOP_RECURSION; | ||
| 340 | } | ||
| 341 | |||
| 342 | bool MetavoxelSystem::findFirstRayHeightfieldIntersection(const glm::vec3& origin, | ||
| 343 | const glm::vec3& direction, float& distance) { | ||
| 344 | RayHeightfieldIntersectionVisitor visitor(origin, direction, getLOD()); | ||
| 345 | guideToAugmented(visitor); | ||
| 346 | if (visitor.intersectionDistance == FLT_MAX) { | ||
| 347 | return false; | ||
| 348 | } | ||
| 349 | distance = visitor.intersectionDistance; | ||
| 350 | return true; | ||
| 351 | } | ||
| 352 | |||
| 353 | class RayVoxelIntersectionVisitor : public RayIntersectionVisitor { | 174 | class RayVoxelIntersectionVisitor : public RayIntersectionVisitor { |
| 354 | public: | 175 | public: |
| 355 | 176 | ||
| @@ -917,6 +738,9 @@ public: · 561 unmodified lines | |||
| 917 | const int SPLAT_COUNT = 4; | 738 | const int SPLAT_COUNT = 4; |
| 918 | const GLint SPLAT_TEXTURE_UNITS[] = { 3, 4, 5, 6 }; | 739 | const GLint SPLAT_TEXTURE_UNITS[] = { 3, 4, 5, 6 }; |
| 919 | 740 | ||
| 741 | static const int EIGHT_BIT_MAXIMUM = 255; | ||
| 742 | static const float EIGHT_BIT_MAXIMUM_RECIPROCAL = 1.0f / EIGHT_BIT_MAXIMUM; | ||
| 743 | |||
| 920 | void HeightfieldBuffer::render(bool cursor) { | 744 | void HeightfieldBuffer::render(bool cursor) { |
| 921 | // initialize textures, etc. on first render | 745 | // initialize textures, etc. on first render |
| 922 | if (_heightTextureID == 0) { | 746 | if (_heightTextureID == 0) { |