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 | 174 | class RayVoxelIntersectionVisitor : public RayIntersectionVisitor { |
| 354 | 175 | public: |
| 355 | 176 | |
| @@ -917,6 +738,9 @@ public: · 561 unmodified lines | ||
| 917 | 738 | const int SPLAT_COUNT = 4; |
| 918 | 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 | 744 | void HeightfieldBuffer::render(bool cursor) { |
| 921 | 745 | // initialize textures, etc. on first render |
| 922 | 746 | if (_heightTextureID == 0) { |